From 1c3cbec661b735b08f8401f93a50a772aff48a62 Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Sun, 26 Nov 2023 11:10:33 +0300 Subject: [PATCH 01/14] [FL-3640] NFC: Felica UID emulation (#3190) * Added basic template of Felica listener * Raw nfc felica listener functions * Added functions to setup chip for felica listener * Cleanup function templates from unnecessary parts * Removed todo comment * Updated api versions * Adjusted chip config for felica * Set proper chip passive target mode for felica * Added felica function to unit tests * Update furi_hal_nfc_felica.c * Removed duplication Co-authored-by: gornekich --- .../debug/unit_tests/nfc/nfc_transport.c | 15 ++ .../helpers/protocol_support/felica/felica.c | 10 +- lib/nfc/nfc.c | 18 ++- lib/nfc/nfc.h | 19 +++ lib/nfc/protocols/felica/felica.h | 2 + lib/nfc/protocols/felica/felica_listener.c | 79 ++++++++++ lib/nfc/protocols/felica/felica_listener.h | 14 ++ .../protocols/felica/felica_listener_defs.h | 13 ++ lib/nfc/protocols/felica/felica_listener_i.h | 21 +++ lib/nfc/protocols/nfc_listener_defs.c | 2 + targets/f7/api_symbols.csv | 2 + targets/f7/furi_hal/furi_hal_nfc_felica.c | 138 +++++++++++++++++- targets/furi_hal_include/furi_hal_nfc.h | 17 +++ 13 files changed, 346 insertions(+), 4 deletions(-) create mode 100644 lib/nfc/protocols/felica/felica_listener.c create mode 100644 lib/nfc/protocols/felica/felica_listener.h create mode 100644 lib/nfc/protocols/felica/felica_listener_defs.h create mode 100644 lib/nfc/protocols/felica/felica_listener_i.h diff --git a/applications/debug/unit_tests/nfc/nfc_transport.c b/applications/debug/unit_tests/nfc/nfc_transport.c index e2e313fdef3..e9f4e21341a 100644 --- a/applications/debug/unit_tests/nfc/nfc_transport.c +++ b/applications/debug/unit_tests/nfc/nfc_transport.c @@ -455,4 +455,19 @@ NfcError nfc_iso15693_listener_tx_sof(Nfc* instance) { return NfcErrorNone; } +NfcError nfc_felica_listener_set_sensf_res_data( + Nfc* instance, + const uint8_t* idm, + const uint8_t idm_len, + const uint8_t* pmm, + const uint8_t pmm_len) { + furi_assert(instance); + furi_assert(idm); + furi_assert(pmm); + furi_assert(idm_len == 8); + furi_assert(pmm_len == 8); + + return NfcErrorNone; +} + #endif diff --git a/applications/main/nfc/helpers/protocol_support/felica/felica.c b/applications/main/nfc/helpers/protocol_support/felica/felica.c index b3e629f4a52..f9c84912161 100644 --- a/applications/main/nfc/helpers/protocol_support/felica/felica.c +++ b/applications/main/nfc/helpers/protocol_support/felica/felica.c @@ -67,8 +67,14 @@ static bool nfc_scene_saved_menu_on_event_felica(NfcApp* instance, uint32_t even return false; } +static void nfc_scene_emulate_on_enter_felica(NfcApp* instance) { + const FelicaData* data = nfc_device_get_data(instance->nfc_device, NfcProtocolFelica); + instance->listener = nfc_listener_alloc(instance->nfc, NfcProtocolFelica, data); + nfc_listener_start(instance->listener, NULL, NULL); +} + const NfcProtocolSupportBase nfc_protocol_support_felica = { - .features = NfcProtocolFeatureNone, + .features = NfcProtocolFeatureEmulateUid, .scene_info = { @@ -102,7 +108,7 @@ const NfcProtocolSupportBase nfc_protocol_support_felica = { }, .scene_emulate = { - .on_enter = nfc_protocol_support_common_on_enter_empty, + .on_enter = nfc_scene_emulate_on_enter_felica, .on_event = nfc_protocol_support_common_on_event_empty, }, }; diff --git a/lib/nfc/nfc.c b/lib/nfc/nfc.c index a7c4fe1a6d4..6475cce435a 100644 --- a/lib/nfc/nfc.c +++ b/lib/nfc/nfc.c @@ -76,7 +76,7 @@ static const FuriHalNfcTech nfc_tech_table[NfcModeNum][NfcTechNum] = { [NfcTechIso14443a] = FuriHalNfcTechIso14443a, [NfcTechIso14443b] = FuriHalNfcTechInvalid, [NfcTechIso15693] = FuriHalNfcTechIso15693, - [NfcTechFelica] = FuriHalNfcTechInvalid, + [NfcTechFelica] = FuriHalNfcTechFelica, }, }; @@ -646,4 +646,20 @@ NfcError nfc_iso15693_listener_tx_sof(Nfc* instance) { return ret; } +NfcError nfc_felica_listener_set_sensf_res_data( + Nfc* instance, + const uint8_t* idm, + const uint8_t idm_len, + const uint8_t* pmm, + const uint8_t pmm_len) { + furi_assert(instance); + furi_assert(idm); + furi_assert(pmm); + + FuriHalNfcError error = + furi_hal_nfc_felica_listener_set_sensf_res_data(idm, idm_len, pmm, pmm_len); + instance->comm_state = NfcCommStateIdle; + return nfc_process_hal_error(error); +} + #endif // APP_UNIT_TESTS diff --git a/lib/nfc/nfc.h b/lib/nfc/nfc.h index 1e8f315a50e..4f7980b0260 100644 --- a/lib/nfc/nfc.h +++ b/lib/nfc/nfc.h @@ -351,6 +351,25 @@ NfcError nfc_iso14443a_listener_set_col_res_data( uint8_t* atqa, uint8_t sak); +/** + * @brief Set FeliCa collision resolution parameters in listener mode. + * + * Configures the NFC hardware for automatic collision resolution. + * + * @param[in,out] instance pointer to the instance to be configured. + * @param[in] idm pointer to a byte array containing the IDm. + * @param[in] idm_len IDm length in bytes. + * @param[in] pmm pointer to a byte array containing the PMm. + * @param[in] pmm_len PMm length in bytes. + * @returns NfcErrorNone on success, any other error code on failure. +*/ +NfcError nfc_felica_listener_set_sensf_res_data( + Nfc* instance, + const uint8_t* idm, + const uint8_t idm_len, + const uint8_t* pmm, + const uint8_t pmm_len); + /** * @brief Send ISO15693 Start of Frame pattern in listener mode * diff --git a/lib/nfc/protocols/felica/felica.h b/lib/nfc/protocols/felica/felica.h index da9d2294ee8..31e040b8a1e 100644 --- a/lib/nfc/protocols/felica/felica.h +++ b/lib/nfc/protocols/felica/felica.h @@ -14,6 +14,8 @@ extern "C" { #define FELICA_FDT_POLL_FC (10000U) #define FELICA_POLL_POLL_MIN_US (1280U) +#define FELICA_FDT_LISTEN_FC (1172) + #define FELICA_SYSTEM_CODE_CODE (0xFFFFU) #define FELICA_TIME_SLOT_1 (0x00U) #define FELICA_TIME_SLOT_2 (0x01U) diff --git a/lib/nfc/protocols/felica/felica_listener.c b/lib/nfc/protocols/felica/felica_listener.c new file mode 100644 index 00000000000..4e6c0578547 --- /dev/null +++ b/lib/nfc/protocols/felica/felica_listener.c @@ -0,0 +1,79 @@ +#include "felica_listener_i.h" + +#include "nfc/protocols/nfc_listener_base.h" + +#define FELICA_LISTENER_MAX_BUFFER_SIZE (64) +#define TAG "Felica" + +FelicaListener* felica_listener_alloc(Nfc* nfc, FelicaData* data) { + furi_assert(nfc); + furi_assert(data); + + FelicaListener* instance = malloc(sizeof(FelicaListener)); + instance->nfc = nfc; + instance->data = data; + instance->tx_buffer = bit_buffer_alloc(FELICA_LISTENER_MAX_BUFFER_SIZE); + instance->rx_buffer = bit_buffer_alloc(FELICA_LISTENER_MAX_BUFFER_SIZE); + + nfc_set_fdt_listen_fc(instance->nfc, FELICA_FDT_LISTEN_FC); + + nfc_config(instance->nfc, NfcModeListener, NfcTechFelica); + nfc_felica_listener_set_sensf_res_data( + nfc, data->idm.data, sizeof(data->idm), data->pmm.data, sizeof(data->pmm)); + + return instance; +} + +void felica_listener_free(FelicaListener* instance) { + furi_assert(instance); + furi_assert(instance->tx_buffer); + + bit_buffer_free(instance->tx_buffer); + bit_buffer_free(instance->rx_buffer); + free(instance); +} + +void felica_listener_set_callback( + FelicaListener* listener, + NfcGenericCallback callback, + void* context) { + UNUSED(listener); + UNUSED(callback); + UNUSED(context); +} + +const FelicaData* felica_listener_get_data(const FelicaListener* instance) { + furi_assert(instance); + furi_assert(instance->data); + + return instance->data; +} + +NfcCommand felica_listener_run(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.protocol == NfcProtocolInvalid); + furi_assert(event.event_data); + + FelicaListener* instance = context; + NfcEvent* nfc_event = event.event_data; + NfcCommand command = NfcCommandContinue; + + if(nfc_event->type == NfcEventTypeListenerActivated) { + instance->state = Felica_ListenerStateActivated; + FURI_LOG_D(TAG, "Activated"); + } else if(nfc_event->type == NfcEventTypeFieldOff) { + instance->state = Felica_ListenerStateIdle; + FURI_LOG_D(TAG, "Field Off"); + } else if(nfc_event->type == NfcEventTypeRxEnd) { + FURI_LOG_D(TAG, "Rx Done"); + } + return command; +} + +const NfcListenerBase nfc_listener_felica = { + .alloc = (NfcListenerAlloc)felica_listener_alloc, + .free = (NfcListenerFree)felica_listener_free, + .set_callback = (NfcListenerSetCallback)felica_listener_set_callback, + .get_data = (NfcListenerGetData)felica_listener_get_data, + .run = (NfcListenerRun)felica_listener_run, +}; \ No newline at end of file diff --git a/lib/nfc/protocols/felica/felica_listener.h b/lib/nfc/protocols/felica/felica_listener.h new file mode 100644 index 00000000000..d210befa574 --- /dev/null +++ b/lib/nfc/protocols/felica/felica_listener.h @@ -0,0 +1,14 @@ +#pragma once + +#include "felica.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct FelicaListener FelicaListener; + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/lib/nfc/protocols/felica/felica_listener_defs.h b/lib/nfc/protocols/felica/felica_listener_defs.h new file mode 100644 index 00000000000..19b252be59e --- /dev/null +++ b/lib/nfc/protocols/felica/felica_listener_defs.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern const NfcListenerBase nfc_listener_felica; + +#ifdef __cplusplus +} +#endif diff --git a/lib/nfc/protocols/felica/felica_listener_i.h b/lib/nfc/protocols/felica/felica_listener_i.h new file mode 100644 index 00000000000..4fa25a16209 --- /dev/null +++ b/lib/nfc/protocols/felica/felica_listener_i.h @@ -0,0 +1,21 @@ +#include "felica_listener.h" + +#include + +typedef enum { + Felica_ListenerStateIdle, + Felica_ListenerStateActivated, +} FelicaListenerState; + +struct FelicaListener { + Nfc* nfc; + FelicaData* data; + FelicaListenerState state; + + BitBuffer* tx_buffer; + BitBuffer* rx_buffer; + + NfcGenericEvent generic_event; + NfcGenericCallback callback; + void* context; +}; \ No newline at end of file diff --git a/lib/nfc/protocols/nfc_listener_defs.c b/lib/nfc/protocols/nfc_listener_defs.c index 31f9bc16c63..2a6167e9cb3 100644 --- a/lib/nfc/protocols/nfc_listener_defs.c +++ b/lib/nfc/protocols/nfc_listener_defs.c @@ -6,6 +6,7 @@ #include #include #include +#include const NfcListenerBase* nfc_listeners_api[NfcProtocolNum] = { [NfcProtocolIso14443_3a] = &nfc_listener_iso14443_3a, @@ -18,4 +19,5 @@ const NfcListenerBase* nfc_listeners_api[NfcProtocolNum] = { [NfcProtocolMfDesfire] = NULL, [NfcProtocolSlix] = &nfc_listener_slix, [NfcProtocolSt25tb] = NULL, + [NfcProtocolFelica] = &nfc_listener_felica, }; diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index c50db0c77cf..9431028abe9 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1287,6 +1287,7 @@ Function,+,furi_hal_nfc_abort,FuriHalNfcError, Function,+,furi_hal_nfc_acquire,FuriHalNfcError, Function,+,furi_hal_nfc_event_start,FuriHalNfcError, Function,+,furi_hal_nfc_event_stop,FuriHalNfcError, +Function,+,furi_hal_nfc_felica_listener_set_sensf_res_data,FuriHalNfcError,"const uint8_t*, const uint8_t, const uint8_t*, const uint8_t" Function,+,furi_hal_nfc_field_detect_start,FuriHalNfcError, Function,+,furi_hal_nfc_field_detect_stop,FuriHalNfcError, Function,+,furi_hal_nfc_field_is_present,_Bool, @@ -2316,6 +2317,7 @@ Function,+,nfc_dict_get_next_key,_Bool,"NfcDict*, uint8_t*, size_t" Function,+,nfc_dict_get_total_keys,uint32_t,NfcDict* Function,+,nfc_dict_is_key_present,_Bool,"NfcDict*, const uint8_t*, size_t" Function,+,nfc_dict_rewind,_Bool,NfcDict* +Function,+,nfc_felica_listener_set_sensf_res_data,NfcError,"Nfc*, const uint8_t*, const uint8_t, const uint8_t*, const uint8_t" Function,+,nfc_free,void,Nfc* Function,+,nfc_iso14443a_listener_set_col_res_data,NfcError,"Nfc*, uint8_t*, uint8_t, uint8_t*, uint8_t" Function,+,nfc_iso14443a_listener_tx_custom_parity,NfcError,"Nfc*, const BitBuffer*" diff --git a/targets/f7/furi_hal/furi_hal_nfc_felica.c b/targets/f7/furi_hal/furi_hal_nfc_felica.c index e4b8ac0ee6b..f762a0ed32b 100644 --- a/targets/f7/furi_hal/furi_hal_nfc_felica.c +++ b/targets/f7/furi_hal/furi_hal_nfc_felica.c @@ -1,6 +1,9 @@ #include "furi_hal_nfc_i.h" #include "furi_hal_nfc_tech_i.h" +// Prevent FDT timer from starting +#define FURI_HAL_NFC_FELICA_LISTENER_FDT_COMP_FC (INT32_MAX) + static FuriHalNfcError furi_hal_nfc_felica_poller_init(FuriHalSpiBusHandle* handle) { // Enable Felica mode, AM modulation st25r3916_change_reg_bits( @@ -50,6 +53,126 @@ static FuriHalNfcError furi_hal_nfc_felica_poller_deinit(FuriHalSpiBusHandle* ha return FuriHalNfcErrorNone; } +static FuriHalNfcError furi_hal_nfc_felica_listener_init(FuriHalSpiBusHandle* handle) { + furi_assert(handle); + st25r3916_write_reg( + handle, + ST25R3916_REG_OP_CONTROL, + ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_rx_en | + ST25R3916_REG_OP_CONTROL_en_fd_auto_efd); + + // Enable Target Felica mode, AM modulation + st25r3916_write_reg( + handle, + ST25R3916_REG_MODE, + ST25R3916_REG_MODE_targ_targ | ST25R3916_REG_MODE_om2 | ST25R3916_REG_MODE_tr_am); + + st25r3916_change_reg_bits( + handle, + ST25R3916_REG_BIT_RATE, + ST25R3916_REG_BIT_RATE_txrate_mask | ST25R3916_REG_BIT_RATE_rxrate_mask, + ST25R3916_REG_BIT_RATE_txrate_212 | ST25R3916_REG_BIT_RATE_rxrate_212); + + // Receive configuration + st25r3916_write_reg( + handle, + ST25R3916_REG_RX_CONF1, + ST25R3916_REG_RX_CONF1_lp0 | ST25R3916_REG_RX_CONF1_hz_12_80khz); + + // AGC enabled, ratio 3:1, squelch after TX + st25r3916_write_reg( + handle, + ST25R3916_REG_RX_CONF2, + ST25R3916_REG_RX_CONF2_agc6_3 | ST25R3916_REG_RX_CONF2_agc_m | + ST25R3916_REG_RX_CONF2_agc_en | ST25R3916_REG_RX_CONF2_sqm_dyn); + // HF operation, full gain on AM and PM channels + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF3, 0x00); + // No gain reduction on AM and PM channels + st25r3916_write_reg(handle, ST25R3916_REG_RX_CONF4, 0x00); + // 10% ASK modulation + st25r3916_write_reg(handle, ST25R3916_REG_TX_DRIVER, ST25R3916_REG_TX_DRIVER_am_mod_10percent); + + // Correlator setup + st25r3916_write_reg( + handle, + ST25R3916_REG_CORR_CONF1, + ST25R3916_REG_CORR_CONF1_corr_s6 | ST25R3916_REG_CORR_CONF1_corr_s4 | + ST25R3916_REG_CORR_CONF1_corr_s2); + + // Sleep mode disable, 424kHz mode off + st25r3916_write_reg(handle, ST25R3916_REG_CORR_CONF2, 0x00); + + st25r3916_write_reg(handle, ST25R3916_REG_MASK_RX_TIMER, 0x02); + + st25r3916_direct_cmd(handle, ST25R3916_CMD_STOP); + uint32_t interrupts = + (ST25R3916_IRQ_MASK_FWL | ST25R3916_IRQ_MASK_TXE | ST25R3916_IRQ_MASK_RXS | + ST25R3916_IRQ_MASK_RXE | ST25R3916_IRQ_MASK_PAR | ST25R3916_IRQ_MASK_CRC | + ST25R3916_IRQ_MASK_ERR1 | ST25R3916_IRQ_MASK_ERR2 | ST25R3916_IRQ_MASK_NRE | + ST25R3916_IRQ_MASK_EON | ST25R3916_IRQ_MASK_EOF | ST25R3916_IRQ_MASK_WU_A_X | + ST25R3916_IRQ_MASK_WU_A); + // Clear interrupts + st25r3916_get_irq(handle); + + st25r3916_write_reg( + handle, + ST25R3916_REG_PASSIVE_TARGET, + ST25R3916_REG_PASSIVE_TARGET_d_106_ac_a | ST25R3916_REG_PASSIVE_TARGET_d_ac_ap2p | + ST25R3916_REG_PASSIVE_TARGET_fdel_1); + // Enable interrupts + st25r3916_mask_irq(handle, ~interrupts); + st25r3916_direct_cmd(handle, ST25R3916_CMD_GOTO_SENSE); + + return FuriHalNfcErrorNone; +} + +static FuriHalNfcError furi_hal_nfc_felica_listener_deinit(FuriHalSpiBusHandle* handle) { + UNUSED(handle); + return FuriHalNfcErrorNone; +} + +static FuriHalNfcEvent furi_hal_nfc_felica_listener_wait_event(uint32_t timeout_ms) { + UNUSED(timeout_ms); + FuriHalNfcEvent event = furi_hal_nfc_wait_event_common(timeout_ms); + + return event; +} + +FuriHalNfcError furi_hal_nfc_felica_listener_tx( + FuriHalSpiBusHandle* handle, + const uint8_t* tx_data, + size_t tx_bits) { + UNUSED(handle); + UNUSED(tx_data); + UNUSED(tx_bits); + return FuriHalNfcErrorNone; +} + +FuriHalNfcError furi_hal_nfc_felica_listener_sleep(FuriHalSpiBusHandle* handle) { + UNUSED(handle); + return FuriHalNfcErrorNone; +} + +FuriHalNfcError furi_hal_nfc_felica_listener_idle(FuriHalSpiBusHandle* handle) { + UNUSED(handle); + return FuriHalNfcErrorNone; +} + +FuriHalNfcError furi_hal_nfc_felica_listener_set_sensf_res_data( + const uint8_t* idm, + const uint8_t idm_len, + const uint8_t* pmm, + const uint8_t pmm_len) { + FuriHalSpiBusHandle* handle = &furi_hal_spi_bus_handle_nfc; + // Write PT Memory + uint8_t pt_memory[19] = {}; + pt_memory[2] = 0x01; + memcpy(pt_memory + 3, idm, idm_len); + memcpy(pt_memory + 3 + idm_len, pmm, pmm_len); + st25r3916_write_ptf_mem(handle, pt_memory, sizeof(pt_memory)); + return FuriHalNfcErrorNone; +} + const FuriHalNfcTechBase furi_hal_nfc_felica = { .poller = { @@ -65,5 +188,18 @@ const FuriHalNfcTechBase furi_hal_nfc_felica = { .rx = furi_hal_nfc_common_fifo_rx, }, - .listener = {}, + .listener = + { + .compensation = + { + .fdt = FURI_HAL_NFC_FELICA_LISTENER_FDT_COMP_FC, + }, + .init = furi_hal_nfc_felica_listener_init, + .deinit = furi_hal_nfc_felica_listener_deinit, + .wait_event = furi_hal_nfc_felica_listener_wait_event, + .tx = furi_hal_nfc_felica_listener_tx, + .rx = furi_hal_nfc_common_fifo_rx, + .sleep = furi_hal_nfc_felica_listener_sleep, + .idle = furi_hal_nfc_felica_listener_idle, + }, }; diff --git a/targets/furi_hal_include/furi_hal_nfc.h b/targets/furi_hal_include/furi_hal_nfc.h index ad4080e2647..3d145d10026 100644 --- a/targets/furi_hal_include/furi_hal_nfc.h +++ b/targets/furi_hal_include/furi_hal_nfc.h @@ -452,6 +452,23 @@ FuriHalNfcError furi_hal_nfc_iso14443a_listener_tx_custom_parity( */ FuriHalNfcError furi_hal_nfc_iso15693_listener_tx_sof(); +/** + * @brief Set FeliCa collision resolution parameters in listener mode. + * + * Configures the NFC hardware for automatic collision resolution. + * + * @param[in] idm pointer to a byte array containing the IDm. + * @param[in] idm_len IDm length in bytes. + * @param[in] pmm pointer to a byte array containing the PMm. + * @param[in] pmm_len PMm length in bytes. + * @returns NfcErrorNone on success, any other error code on failure. +*/ +FuriHalNfcError furi_hal_nfc_felica_listener_set_sensf_res_data( + const uint8_t* idm, + const uint8_t idm_len, + const uint8_t* pmm, + const uint8_t pmm_len); + #ifdef __cplusplus } #endif From f9101d80840b4b7ef7146e41bba99aac881bbfca Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Sun, 26 Nov 2023 12:20:49 +0400 Subject: [PATCH 02/14] [FL-3686] Mifare Classic fixes (#3221) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update Mifare Classic generators to create more accuate data * Check the transfer buffer validity for NACK * Fix the AC issues * CRC errors don't really affect emulation, checking for them isn't worth it * Make ATQA logic a bit easier to understand * mf classic: change log level * mf classic: fix log level Co-authored-by: gornekich Co-authored-by: あく --- lib/nfc/helpers/nfc_data_generator.c | 41 ++++++++++++------- lib/nfc/protocols/mf_classic/mf_classic.c | 13 +++--- lib/nfc/protocols/mf_classic/mf_classic.h | 2 + .../mf_classic/mf_classic_listener.c | 25 ++++++++++- .../mf_classic/mf_classic_listener_i.h | 1 + 5 files changed, 60 insertions(+), 22 deletions(-) diff --git a/lib/nfc/helpers/nfc_data_generator.c b/lib/nfc/helpers/nfc_data_generator.c index 011f9f6db7d..21f062605b6 100644 --- a/lib/nfc/helpers/nfc_data_generator.c +++ b/lib/nfc/helpers/nfc_data_generator.c @@ -329,9 +329,23 @@ static void nfc_generate_mf_classic_uid(uint8_t* uid, uint8_t length) { static void nfc_generate_mf_classic_common(MfClassicData* data, uint8_t uid_len, MfClassicType type) { data->iso14443_3a_data->uid_len = uid_len; - data->iso14443_3a_data->atqa[0] = 0x44; + data->iso14443_3a_data->atqa[0] = 0x00; data->iso14443_3a_data->atqa[1] = 0x00; - data->iso14443_3a_data->sak = 0x08; + data->iso14443_3a_data->sak = 0x00; + // Calculate the proper ATQA and SAK + if(uid_len == 7) { + data->iso14443_3a_data->atqa[0] |= 0x40; + } + if(type == MfClassicType1k) { + data->iso14443_3a_data->atqa[0] |= 0x04; + data->iso14443_3a_data->sak = 0x08; + } else if(type == MfClassicType4k) { + data->iso14443_3a_data->atqa[0] |= 0x02; + data->iso14443_3a_data->sak = 0x18; + } else if(type == MfClassicTypeMini) { + data->iso14443_3a_data->atqa[0] |= 0x08; + data->iso14443_3a_data->sak = 0x09; + } data->type = type; } @@ -343,6 +357,11 @@ static void nfc_generate_mf_classic_sector_trailer(MfClassicData* data, uint8_t sec_tr->access_bits.data[2] = 0x80; sec_tr->access_bits.data[3] = 0x69; // Nice + for(int i = 0; i < 6; i++) { + sec_tr->key_a.data[i] = 0xFF; + sec_tr->key_b.data[i] = 0xFF; + } + mf_classic_set_block_read(data, block, &data->block[block]); mf_classic_set_key_found( data, mf_classic_get_sector_by_block(block), MfClassicKeyTypeA, 0xFFFFFFFFFFFF); @@ -396,41 +415,35 @@ static void nfc_generate_mf_classic(NfcDevice* nfc_device, uint8_t uid_len, MfCl uint16_t block_num = mf_classic_get_total_block_num(type); if(type == MfClassicType4k) { - // Set every block to 0xFF + // Set every block to 0x00 for(uint16_t i = 1; i < block_num; i++) { if(mf_classic_is_sector_trailer(i)) { nfc_generate_mf_classic_sector_trailer(mfc_data, i); } else { - memset(&mfc_data->block[i].data, 0xFF, 16); + memset(&mfc_data->block[i].data, 0x00, 16); } mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); } - // Set SAK to 18 - mfc_data->iso14443_3a_data->sak = 0x18; } else if(type == MfClassicType1k) { - // Set every block to 0xFF + // Set every block to 0x00 for(uint16_t i = 1; i < block_num; i++) { if(mf_classic_is_sector_trailer(i)) { nfc_generate_mf_classic_sector_trailer(mfc_data, i); } else { - memset(&mfc_data->block[i].data, 0xFF, 16); + memset(&mfc_data->block[i].data, 0x00, 16); } mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); } - // Set SAK to 08 - mfc_data->iso14443_3a_data->sak = 0x08; } else if(type == MfClassicTypeMini) { - // Set every block to 0xFF + // Set every block to 0x00 for(uint16_t i = 1; i < block_num; i++) { if(mf_classic_is_sector_trailer(i)) { nfc_generate_mf_classic_sector_trailer(mfc_data, i); } else { - memset(&mfc_data->block[i].data, 0xFF, 16); + memset(&mfc_data->block[i].data, 0x00, 16); } mf_classic_set_block_read(mfc_data, i, &mfc_data->block[i]); } - // Set SAK to 09 - mfc_data->iso14443_3a_data->sak = 0x09; } nfc_generate_mf_classic_block_0( diff --git a/lib/nfc/protocols/mf_classic/mf_classic.c b/lib/nfc/protocols/mf_classic/mf_classic.c index 400cf0d7fb3..e68e8c71872 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.c +++ b/lib/nfc/protocols/mf_classic/mf_classic.c @@ -606,6 +606,7 @@ static bool mf_classic_is_allowed_access_sector_trailer( uint8_t* access_bits_arr = sec_tr->access_bits.data; uint8_t AC = ((access_bits_arr[1] >> 5) & 0x04) | ((access_bits_arr[2] >> 2) & 0x02) | ((access_bits_arr[2] >> 7) & 0x01); + FURI_LOG_T("NFC", "AC: %02X", AC); switch(action) { case MfClassicActionKeyARead: { @@ -615,20 +616,20 @@ static bool mf_classic_is_allowed_access_sector_trailer( case MfClassicActionKeyBWrite: { return ( (key_type == MfClassicKeyTypeA && (AC == 0x00 || AC == 0x01)) || - (key_type == MfClassicKeyTypeB && (AC == 0x04 || AC == 0x03))); + (key_type == MfClassicKeyTypeB && + (AC == 0x00 || AC == 0x04 || AC == 0x03 || AC == 0x01))); } case MfClassicActionKeyBRead: { - return (key_type == MfClassicKeyTypeA && (AC == 0x00 || AC == 0x02 || AC == 0x01)); + return (key_type == MfClassicKeyTypeA && (AC == 0x00 || AC == 0x02 || AC == 0x01)) || + (key_type == MfClassicKeyTypeB && (AC == 0x00 || AC == 0x02 || AC == 0x01)); } case MfClassicActionACRead: { - return ( - (key_type == MfClassicKeyTypeA) || - (key_type == MfClassicKeyTypeB && !(AC == 0x00 || AC == 0x02 || AC == 0x01))); + return ((key_type == MfClassicKeyTypeA) || (key_type == MfClassicKeyTypeB)); } case MfClassicActionACWrite: { return ( (key_type == MfClassicKeyTypeA && (AC == 0x01)) || - (key_type == MfClassicKeyTypeB && (AC == 0x03 || AC == 0x05))); + (key_type == MfClassicKeyTypeB && (AC == 0x01 || AC == 0x03 || AC == 0x05))); } default: return false; diff --git a/lib/nfc/protocols/mf_classic/mf_classic.h b/lib/nfc/protocols/mf_classic/mf_classic.h index f180411df52..146e6a6f157 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic.h +++ b/lib/nfc/protocols/mf_classic/mf_classic.h @@ -19,6 +19,8 @@ extern "C" { #define MF_CLASSIC_CMD_HALT_LSB (0x00) #define MF_CLASSIC_CMD_ACK (0x0A) #define MF_CLASSIC_CMD_NACK (0x00) +#define MF_CLASSIC_CMD_NACK_TRANSFER_INVALID (0x04) +#define MF_CLASSIC_CMD_NACK_TRANSFER_CRC_ERROR (0x01) #define MF_CLASSIC_TOTAL_SECTORS_MAX (40) #define MF_CLASSIC_TOTAL_BLOCKS_MAX (256) diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener.c b/lib/nfc/protocols/mf_classic/mf_classic_listener.c index f7bd5b3f45f..fb12ba8a95c 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_listener.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener.c @@ -34,6 +34,7 @@ static void mf_classic_listener_reset_state(MfClassicListener* instance) { instance->cmd_in_progress = false; instance->current_cmd_handler_idx = 0; instance->transfer_value = 0; + instance->transfer_valid = false; instance->value_cmd = MfClassicValueCommandInvalid; } @@ -154,7 +155,7 @@ static MfClassicListenerCommand uint32_t nt_num = nfc_util_bytes2num(instance->auth_context.nt.data, sizeof(MfClassicNt)); uint32_t secret_poller = ar_num ^ crypto1_word(instance->crypto, 0, 0); if(secret_poller != prng_successor(nt_num, 64)) { - FURI_LOG_D( + FURI_LOG_T( TAG, "Wrong reader key: %08lX != %08lX", secret_poller, prng_successor(nt_num, 64)); mf_classic_listener_reset_state(instance); break; @@ -272,6 +273,17 @@ static MfClassicListenerCommand mf_classic_listener_write_block_second_part_hand if(mf_classic_is_sector_trailer(block_num)) { MfClassicSectorTrailer* sec_tr = (MfClassicSectorTrailer*)█ + + // Check if any writing is allowed + if(!mf_classic_is_allowed_access( + instance->data, block_num, key_type, MfClassicActionKeyAWrite) && + !mf_classic_is_allowed_access( + instance->data, block_num, key_type, MfClassicActionKeyBWrite) && + !mf_classic_is_allowed_access( + instance->data, block_num, key_type, MfClassicActionACWrite)) { + break; + } + if(mf_classic_is_allowed_access( instance->data, block_num, key_type, MfClassicActionKeyAWrite)) { bit_buffer_write_bytes_mid(buff, sec_tr->key_a.data, 0, sizeof(MfClassicKey)); @@ -338,6 +350,7 @@ static MfClassicListenerCommand break; } + instance->transfer_valid = true; instance->cmd_in_progress = true; instance->current_cmd_handler_idx++; command = MfClassicListenerCommandAck; @@ -382,6 +395,7 @@ static MfClassicListenerCommand } instance->transfer_value += data; + instance->transfer_valid = true; instance->cmd_in_progress = true; instance->current_cmd_handler_idx++; @@ -411,6 +425,7 @@ static MfClassicListenerCommand mf_classic_value_to_block( instance->transfer_value, block_num, &instance->data->block[block_num]); instance->transfer_value = 0; + instance->transfer_valid = false; command = MfClassicListenerCommandAck; } while(false); @@ -581,7 +596,13 @@ NfcCommand mf_classic_listener_run(NfcGenericEvent event, void* context) { if(mfc_command == MfClassicListenerCommandAck) { mf_classic_listener_send_short_frame(instance, MF_CLASSIC_CMD_ACK); } else if(mfc_command == MfClassicListenerCommandNack) { - mf_classic_listener_send_short_frame(instance, MF_CLASSIC_CMD_NACK); + // Calculate nack based on the transfer buffer validity + uint8_t nack = MF_CLASSIC_CMD_NACK; + if(!instance->transfer_valid) { + nack += MF_CLASSIC_CMD_NACK_TRANSFER_INVALID; + } + + mf_classic_listener_send_short_frame(instance, nack); } else if(mfc_command == MfClassicListenerCommandSilent) { command = NfcCommandReset; } else if(mfc_command == MfClassicListenerCommandSleep) { diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h b/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h index 4b040bec12c..52273be9c22 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener_i.h @@ -42,6 +42,7 @@ struct MfClassicListener { // Value operation data int32_t transfer_value; + bool transfer_valid; MfClassicValueCommand value_cmd; NfcGenericEvent generic_event; From ff129e524a89fddaed7b84a4a5af5928daa97c42 Mon Sep 17 00:00:00 2001 From: Evgeny Stepanischev Date: Thu, 30 Nov 2023 12:38:48 +0300 Subject: [PATCH 03/14] Allows you to use UCS-2 in canvas_glyph_width (#3226) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * allows you to use UCS-2 in canvas_glyph_width * Sync API Symbols Co-authored-by: あく --- applications/services/gui/canvas.c | 2 +- applications/services/gui/canvas.h | 2 +- targets/f18/api_symbols.csv | 4 ++-- targets/f7/api_symbols.csv | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/applications/services/gui/canvas.c b/applications/services/gui/canvas.c index 85c0528530d..44adcd93951 100644 --- a/applications/services/gui/canvas.c +++ b/applications/services/gui/canvas.c @@ -202,7 +202,7 @@ uint16_t canvas_string_width(Canvas* canvas, const char* str) { return u8g2_GetStrWidth(&canvas->fb, str); } -uint8_t canvas_glyph_width(Canvas* canvas, char symbol) { +uint8_t canvas_glyph_width(Canvas* canvas, uint16_t symbol) { furi_assert(canvas); return u8g2_GetGlyphWidth(&canvas->fb, symbol); } diff --git a/applications/services/gui/canvas.h b/applications/services/gui/canvas.h index f34d02bfbac..a369e213bd9 100644 --- a/applications/services/gui/canvas.h +++ b/applications/services/gui/canvas.h @@ -214,7 +214,7 @@ uint16_t canvas_string_width(Canvas* canvas, const char* str); * * @return width in pixels */ -uint8_t canvas_glyph_width(Canvas* canvas, char symbol); +uint8_t canvas_glyph_width(Canvas* canvas, uint16_t symbol); /** Draw bitmap picture at position defined by x,y. * diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index d861d851173..7835718defa 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,46.0,, +Version,+,47.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -633,7 +633,7 @@ Function,+,canvas_draw_str_aligned,void,"Canvas*, uint8_t, uint8_t, Align, Align Function,+,canvas_draw_triangle,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, CanvasDirection" Function,+,canvas_draw_xbm,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, const uint8_t*" Function,+,canvas_get_font_params,const CanvasFontParameters*,"const Canvas*, Font" -Function,+,canvas_glyph_width,uint8_t,"Canvas*, char" +Function,+,canvas_glyph_width,uint8_t,"Canvas*, uint16_t" Function,+,canvas_height,uint8_t,const Canvas* Function,+,canvas_invert_color,void,Canvas* Function,+,canvas_reset,void,Canvas* diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 9431028abe9..f31349f9c9d 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,46.0,, +Version,+,47.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -722,7 +722,7 @@ Function,+,canvas_draw_str_aligned,void,"Canvas*, uint8_t, uint8_t, Align, Align Function,+,canvas_draw_triangle,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, CanvasDirection" Function,+,canvas_draw_xbm,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, const uint8_t*" Function,+,canvas_get_font_params,const CanvasFontParameters*,"const Canvas*, Font" -Function,+,canvas_glyph_width,uint8_t,"Canvas*, char" +Function,+,canvas_glyph_width,uint8_t,"Canvas*, uint16_t" Function,+,canvas_height,uint8_t,const Canvas* Function,+,canvas_invert_color,void,Canvas* Function,+,canvas_reset,void,Canvas* From a849d49c92ff6d015d558717c9bb5c72ad074d86 Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Thu, 30 Nov 2023 13:51:38 +0400 Subject: [PATCH 04/14] [FL-3682] Add the secret door animation (#3233) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .../external/L2_Secret_door_128x64/frame_0.png | Bin 0 -> 1648 bytes .../external/L2_Secret_door_128x64/frame_1.png | Bin 0 -> 1655 bytes .../external/L2_Secret_door_128x64/frame_10.png | Bin 0 -> 1552 bytes .../external/L2_Secret_door_128x64/frame_11.png | Bin 0 -> 1548 bytes .../external/L2_Secret_door_128x64/frame_12.png | Bin 0 -> 1577 bytes .../external/L2_Secret_door_128x64/frame_13.png | Bin 0 -> 1541 bytes .../external/L2_Secret_door_128x64/frame_14.png | Bin 0 -> 1578 bytes .../external/L2_Secret_door_128x64/frame_15.png | Bin 0 -> 1897 bytes .../external/L2_Secret_door_128x64/frame_16.png | Bin 0 -> 1918 bytes .../external/L2_Secret_door_128x64/frame_17.png | Bin 0 -> 1882 bytes .../external/L2_Secret_door_128x64/frame_18.png | Bin 0 -> 1907 bytes .../external/L2_Secret_door_128x64/frame_19.png | Bin 0 -> 1974 bytes .../external/L2_Secret_door_128x64/frame_2.png | Bin 0 -> 1636 bytes .../external/L2_Secret_door_128x64/frame_20.png | Bin 0 -> 1937 bytes .../external/L2_Secret_door_128x64/frame_21.png | Bin 0 -> 1894 bytes .../external/L2_Secret_door_128x64/frame_22.png | Bin 0 -> 1923 bytes .../external/L2_Secret_door_128x64/frame_23.png | Bin 0 -> 1966 bytes .../external/L2_Secret_door_128x64/frame_24.png | Bin 0 -> 1958 bytes .../external/L2_Secret_door_128x64/frame_25.png | Bin 0 -> 1946 bytes .../external/L2_Secret_door_128x64/frame_26.png | Bin 0 -> 1881 bytes .../external/L2_Secret_door_128x64/frame_27.png | Bin 0 -> 1902 bytes .../external/L2_Secret_door_128x64/frame_28.png | Bin 0 -> 1969 bytes .../external/L2_Secret_door_128x64/frame_29.png | Bin 0 -> 2094 bytes .../external/L2_Secret_door_128x64/frame_3.png | Bin 0 -> 1599 bytes .../external/L2_Secret_door_128x64/frame_30.png | Bin 0 -> 2028 bytes .../external/L2_Secret_door_128x64/frame_31.png | Bin 0 -> 1922 bytes .../external/L2_Secret_door_128x64/frame_32.png | Bin 0 -> 1900 bytes .../external/L2_Secret_door_128x64/frame_33.png | Bin 0 -> 1938 bytes .../external/L2_Secret_door_128x64/frame_34.png | Bin 0 -> 1923 bytes .../external/L2_Secret_door_128x64/frame_35.png | Bin 0 -> 1913 bytes .../external/L2_Secret_door_128x64/frame_36.png | Bin 0 -> 1937 bytes .../external/L2_Secret_door_128x64/frame_37.png | Bin 0 -> 1944 bytes .../external/L2_Secret_door_128x64/frame_38.png | Bin 0 -> 1683 bytes .../external/L2_Secret_door_128x64/frame_39.png | Bin 0 -> 1662 bytes .../external/L2_Secret_door_128x64/frame_4.png | Bin 0 -> 1618 bytes .../external/L2_Secret_door_128x64/frame_40.png | Bin 0 -> 1725 bytes .../external/L2_Secret_door_128x64/frame_41.png | Bin 0 -> 1654 bytes .../external/L2_Secret_door_128x64/frame_42.png | Bin 0 -> 1495 bytes .../external/L2_Secret_door_128x64/frame_43.png | Bin 0 -> 1440 bytes .../external/L2_Secret_door_128x64/frame_44.png | Bin 0 -> 1445 bytes .../external/L2_Secret_door_128x64/frame_45.png | Bin 0 -> 1464 bytes .../external/L2_Secret_door_128x64/frame_46.png | Bin 0 -> 1446 bytes .../external/L2_Secret_door_128x64/frame_47.png | Bin 0 -> 1369 bytes .../external/L2_Secret_door_128x64/frame_48.png | Bin 0 -> 1529 bytes .../external/L2_Secret_door_128x64/frame_49.png | Bin 0 -> 1851 bytes .../external/L2_Secret_door_128x64/frame_5.png | Bin 0 -> 1625 bytes .../external/L2_Secret_door_128x64/frame_50.png | Bin 0 -> 2132 bytes .../external/L2_Secret_door_128x64/frame_51.png | Bin 0 -> 2258 bytes .../external/L2_Secret_door_128x64/frame_52.png | Bin 0 -> 1615 bytes .../external/L2_Secret_door_128x64/frame_6.png | Bin 0 -> 1591 bytes .../external/L2_Secret_door_128x64/frame_7.png | Bin 0 -> 1671 bytes .../external/L2_Secret_door_128x64/frame_8.png | Bin 0 -> 1612 bytes .../external/L2_Secret_door_128x64/frame_9.png | Bin 0 -> 1575 bytes .../external/L2_Secret_door_128x64/meta.txt | 14 ++++++++++++++ assets/dolphin/external/manifest.txt | 7 +++++++ 55 files changed, 21 insertions(+) create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_0.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_1.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_10.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_11.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_12.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_13.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_14.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_15.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_16.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_17.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_18.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_19.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_2.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_20.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_21.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_22.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_23.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_24.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_25.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_26.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_27.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_28.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_29.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_3.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_30.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_31.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_32.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_33.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_34.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_35.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_36.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_37.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_38.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_39.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_4.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_40.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_41.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_42.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_43.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_44.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_45.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_46.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_47.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_48.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_49.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_5.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_50.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_51.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_52.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_6.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_7.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_8.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/frame_9.png create mode 100644 assets/dolphin/external/L2_Secret_door_128x64/meta.txt diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_0.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_0.png new file mode 100644 index 0000000000000000000000000000000000000000..8f29d5e2c7065c50e1ff361f437e85f24cfd1113 GIT binary patch literal 1648 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 b3!?u3+$H50?G|~m00000NkvXXu0mjf9Le=- literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_13.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_13.png new file mode 100644 index 0000000000000000000000000000000000000000..38171c273ca522acbac21d3154c54aca99cd5db0 GIT binary patch literal 1541 zcmV+g2KxDlP)|T}FV6v(CIEwG9Yq(9LZN z5mox)v3Ttk;ETODYW+HZC!^3e1Uwqw5b$t(3Gi@i%K=I$RBNSD$|dVPE!RQyyCnx` z#<+?Ee7z?iqTfVTgKs=;p32X+PJ3}pD3o^ zZAoC11U;*f`TKEC0;=DwRlo=d(0SYQPc(i5qTlUhAW8y$4GkAhHhzPr-{~p<&EmBr zPBIuzTr^ThYt9<~ZdJmlZY5~?eItN2nWpd=<6F;4BtX_c$&!hP4y`$6jgK6XsWK2T zWMoV~R`UcsDZJzm-Qtx*+1-F^-&6Vkky5Q6(}0kme@?>8_C^VD_uS(T2`HEYNXpNE z6tg1t`Ex6AcjKZs4-y3k;KilY%CTzy(S$F<&94YCk(T(MEFQFn_8d$Aq)yL(<@&FB zhv4A~j~GGZ9ZTqKVAckAmS3}b;<9UAY6afvckeA9sMBLgszq4Q{ToH*{7C7FlBU1D zid=sPAPK{--NnUm?2i8)Jo$F(^svgO{@y3HS9yH4;$pUCG*-~u4R^v@yBqR(W*B0&myX10 zE7L|2)~uFtbl%n84<SCwyi2x6f-66|pHAhOlm9LXCPkvTkKy3tRn?V{y+R674pV4G=77^vogp8Rk zWLBwYdVq|wY&51@0Wsj|cFK-!K~EcC=qt$980#cdB|o>BjaNQFkK1%R2c)@0*c+mOekl_(bu%L~9}U)j}yn zG<@ykNNZ9+GF^b36gkUeRm){T(Nzn9SRTk2r*_9uhji9!$ z_DM8f&qrIqcP1BF^RGJj83d`d{=N=IPQ2H))i!G-OY?fdMSD{&H( zfKK4dCZevezkfFZSj{bo1k(Pa#$0{+xr{F_n{VHvhTs{nH}-BuM!=0Bg|3yIPpz65 zLGR(uzYE}>t2cmc9h5?XP zDHpnb=1yerl0XgK9BJp=Lit!i!5_@$J6 z{~y3Jz7|v4^+;&QOt>_{qaMmD!~1f4#@J#NFtz(2_{m0vMCNJNq@S-qG=?L|pyUZx z8~^kGT-p8iRX{dlUDxJpa(afpI%m+<^GJR5=SxyHS7!7iNrpz5+}1{n-ykK7cTEr_ zJ@D&0J`e5YED0K<4M&AUlxoS35@NOI>t)Y&=OcO*JAqP+?FEl0u2)2a`5utXde8`q zA{utGjf&iFP(1)wo~B4?;}PTWIS>+f>qU%i%@>8WUQe!UbJ8;!i6z6&?C;Z2YqkGdc*LD%jYoibtJNp| r(@~1@8$r=n>Mb(srbaLl!k&nK#X!8+KN{(N00000NkvXXu0mjf#LVgb literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_14.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_14.png new file mode 100644 index 0000000000000000000000000000000000000000..3eb9a1f6327dffcc27476326c75d9b48c1f75cf8 GIT binary patch literal 1578 zcmV+_2G#kAP)74%zv8YW9hk9RX$=SXVtYs|Lb-cW?65(P5P$ zFp5ZPb|vg9E5C}2^1BPKPf;Eu;9%Q$5L8GG}W0bmN%uSYw za6|B-fd;9T@YY*0%tWMUy;YU{TPLvMAuGVTg5hUgG{~HjnU9F3vJ6I_p6)B=B?%UT zk-N7R4JZa%b;To|5kL#oJcrF@Dq9~&>!Wmz zDqr(+}{b*KG&{7T0!}35usWTkJeRPc!>ZRaHU0V z4|JW>GX7*kpvd$}uCD%3KM$#srFpmH!IFmqyx$_UG=O8#qG)9xADO6m6`l<%fY;v$ zvhJ@GQYC9OK&)};%vA){0gtCH!}roJorCWm)M~X37azAg-Xba@1R4!KJtAmPlfDA@ zk;8%%aiiDEZQK4*02Q{CyCVf2B}!YbK}!ptWC&EA+Evk$anv9@J$Q5;$MO0*fmNkv zj3G)KWwP54W?iee0{MAS+3_{ntG9=R@GYRr7&64sbCFoBc+4WJe9LH~w9wBig-WmZ zzFW>XFLe#4lG5v{(4m#<~ktEsW2U?}IW@^{8rk$nJ~dlnI_9IP=n2mQN|K z(}*;ZQY>fE#=GPT0Drdt%hNKOWg>)!OrFH~o-t&=l`W+q$y1|y)Aci6qcFb@FuJ+N zthcUe`Bu)(L?2EELi13{FU2e+cj!rs03$;71gi;26B^FXFfE-EQ9cdx(z%o_>u>&g zma;2O`WQW2Vmb?nU`@ys`aI=R#YV!Z literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_15.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_15.png new file mode 100644 index 0000000000000000000000000000000000000000..6244074889e65942a79e6f658f1ad82e989cb88a GIT binary patch literal 1897 zcmV-v2bTDWP)ewA(h)M%0 z3)Z2kVA_eDJ6@^#tDx9^p&gnTtz-oD%-ggMf0N*|_SAa+$&B~1%-lf)MIYF)uO`8c z9e)LhGju;+{lhLIDEh#s$17|9-FEzlZph|m@wSVONT3d!)#^wejM!U+-8Fv3FK;i) zh9e|-XKeKjWUy_JO++k(47-TX?Oqjpw8N2|Z0$$0=1&Pwu(CWSb?UK?G$CbV^tSySSsl-+^rN_`jL(WOjbm^dvJ-6u#P)_4NxF zrBa_FS1xUrgV4a4bLvEt{!vY3Bp40GY}#K9w0=lDD5={zeuAWinYnQCsxc`;}!K+onR+D}s-NtzutI|8{-|y^r*RkVuWPprG_s0qZkT z7Dji{CwD&6KGiait^cn+r<++;KO!r3|5f`}!pV1+NO z{aK5Y0BS&1Axr-e89Wi9vT)a(@8=TPok8!P{w#cFuvKI!-nZ)u#E4<HQ_*T)+b1d^)s#D$_OlZ}#def2zJ>s;>0ea!9ffv!f8L3J#3Nd8^m&zr zP}`#C%$I)sDgrRrU2XsF$W9WT2(}HgQ`w!UeOA|5Nn&F#+w!a6JAy5+UmTXAds~J` zEUF5*v70N*v52XXRXSBUF!6tUueS(ITp-oDS3!@9jsKLJ^RUCBQ6DeeCzMg{zD) zLjvZrMJ5z8-~LGguz*LqNIf~Ae$nZm5_})*(F|a1K2ijZzzV@C=dG4NgixN_c53iZ zKjat70NF9|v8R9vY|xP){A2>G?)*w-P{!-+ExwWfez#`}H+$5o_+`hAb~bBQ)dtb& z;-3_OUiGu1R>ukr;M=1ykv-*oK&D?Z5oWa*ZTiEP==ibk+wC>blW z`{UEUkOA14+AnUjuruWX^=0?6;9LKh-)h_QEc`6|iHOquh%KfkD!xR%DZ!79m8=c& zq4)Vp0N!&#XTqX%tvy!;jC>{?}@NXot@zeN_l%zS;IDxPB~uQc(gL zwMFyz3Ib%QJv&B4$V6Xelcj4$$n2Cdk^$^J-|n^qP=ck@bemFDyKF~gN52fHBr#iv z2r7xy;J5bB44|B?`!nT5N@PDG&WZyRIvPg4WTz2(Wc73Kejmrfz6-E*5v5j?`q-7h z5=Zq%X%`7lYbPpW=UW4WiISFs{gY@ z%E)tT0o|5DC=Y55 zDiB$tGIAA3wh~~)#Ly1Tc6xS={I!0wqa^a=AAUto`aWvbn-eYdLwcNsTqRosUw*u;w{MUcQm}%#BPm?f1S4av jBvaPT`!kA&bRGWzWq*skP+kMC00000NkvXXu0mjfeO{Yi literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_16.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_16.png new file mode 100644 index 0000000000000000000000000000000000000000..f1306c2eb4a149aad4d800fe64d0ef950c8ec0d5 GIT binary patch literal 1918 zcmV-^2Z8vBP)Wg zUzxEx8*~-S27jG!y4}BXZGL{mpKGo4SpQ}KrYs!@%!-)C^x`IV=IGd{;uR5}%^Tg@ zGec*u*m#ETOkp&s!Ymt$ve9Pl>g(bi={~X}S|6@6OXqAXK2Pmy&)n`KqI(k75OIjUI|5i-KyJB-v*yt~#{cC8g>0}Q@ynTmjVzYM!o9C-Ns7P!&Hiz(jL~EIvt9ojEIe%$6$} zzthOi*3gam2$_!Wok-}^8jmX?U)`Xp;X0jv()m|q1E%-;q{f=k>^&M#=~Kpd`OKNv zWKKo?M8j7_{i`r?3P5zDALY@(OukFp$=ZJs@u$%}J$~dAfas8d$*af1Zl=NK-Oaor z-B&iUjNtWE1YqKbDRVsAG<>f*>uTqB*1wZw*qDzZfJfCOvv*NOVe(mnnDrf3I=|BZW+Z5h`BVZJ zxn!bRRJRu$DBA{X&|e4B3m-N?3Y1TB8qY~ z`dOWi<}rDu>ni7aJC*rx9T^dB+XF<4Vw+=#G6Q!0ooHl@;#HB)`VrPRGNNKnVz?~< z49NQGI9BO8C4zsx>wNXJk-g8z=W%-iAa)u%rel`~Hpai}I$w2ObqcADm}~t)0!#vl z;Gsk$%Lvtc>S=+=qkW3L+Y_KVmic>puL4O>rDgv!lVOpl_72f}oec2fdiP`CE-+22 z^4MUV%-?Mo*}UpHBE7dIK&O^6Iee~e9+Opd;M`2V(lb;9$kzJ5Uf_-d$h!S(%v$kp z(7X%+9g&rmOb^OuM>@64CcX*GsDKhr_&k?`_vw_Es^HH~r^*SRPs$(U)$GMp8 zQREwb#qR?-Cq^d@^<+>rl3w=L5ukE5laD^4RL?r^alWka#KshV zRx^N-#eN+Dx*vF0w0T`s$M1EaT-C)#{YaOvkxbMV{J9cY2t zkI23Spd5R~y7+FNVLwNwoyTL~pNFgI?$wBDo|0Z|%uW_Sy}NerWRnQ~0~oIB*L(-? zO!v_qHF+5M_>~Z^QzXxtOtz+pxw9kU*nbq+HS#2Ls7Jl18%CR1(-b|MfYQiKAtIU0 z@zG6ScY~sIj$`qCmH||~s*TK+tAM8r|J?9a0#u7v&co5Q8mH>naejtM&vdr&dToCH zY>NP=tnDr^bBeb|%>Z~mMFM4ASXy4yKr`FuDL`>#8I`Zt87uk0O z{QTdz`BzWQny=~_>8W%uoH#$ydn%9iy@~{D1^-iMHw)}y#{rS8-C8~6{7PR}?rP`b zoL|=Y`addmYq|eGGMBme*a literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_17.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_17.png new file mode 100644 index 0000000000000000000000000000000000000000..ed8d96bab11cdcdde1efdc162669fa9ac5911ee8 GIT binary patch literal 1882 zcmV-g2c`IlP)>mitID=)!YQzt=};hXoLG?^ zw)bvhjD3tT_I)2?jInLon3&Hd<~w|j?=ALyAKSKlyPgdkFS=SkKjBwrEZcAO9JcX~ z0Eoy~hX}L%StO_g-7efG0*`)LsB5SaIkSsnY=7JK7U61&aP{CbKNWO{E&DQ~e?&^6 z1wEStciQ=tKw(O*&P^f0zVCktfI;Yzp-KdtSQl3fzUmk2gU_blRh!ZMwr%6h9A{)u z7LBpid*>}u6?YH5I`5ABE4E+Cz|(joXGO({$NJe`9p`GnxBhqYwfEdxqw1O=-geMv zf$R=uzk7YW#m9+OcgEF%Z|8JY(WdO^%H|nEPyhs5)M(I1K~N3Y4r2DN7W~f6uabZ% z=TYqYUMIlpXalOGhzb$Lh^yw6xpf7)L9Zx4SK`qIu1SjkWBknXRt+LDtWtz4kzhse z8Nu!SS$N?tt^!Gb0qhb1(Ou-T&{ZUso<5~i*7rGPTLCOsO27dXBCzMo@!t;q^sl2x zw*99A&+uC1gqIR5G9svHVO3S#!I6TG&4=0c?iJsv@qA^)TNO(6?Tx9Xg(wKoxGT^J zy0YW(-Re1bd;LL_}ci7*-UDM}v>;)wB{7a?v;ye=nr~2%Nk}gh)2eP=wAr zGJ8kT$`M>z0W7@T8|`L>ND)~7vkSk-o_)`hDjJ8)gN|_*0!(;8&uRk(Cbi5)Ca0{> zM1Q-d2(O6sQVR1UOdEG2z!>Y)V8RPXb}I13QAohrF+}sq>IXK*AHLm@027%S*k=kn zsZ|Tb?0t3TM>U7y1KMHNOMD0Df=$|crT__*Romzb^R2t{I~BjR&5o1odTRoVQQNhu zxUhYA-Cy!Qu2#f?( zBFuhhuad(R5@f;3`a}qcbLS!u;T_SU${5>5U`yp4$uhs9zES${j(VB@p4~?gV2nBm zCe-|1Jym!

NgTqtDDYR>z?IOMePpg^C1wCyCjnvR}NKp_9*#AgT!-qX24E?zLt8 zj-(HdG?g8n%~SQkv+iQ7`zY1Xe-3;6`--yGQ>$^@&ae?1U59L9*Oh z0X(R?DGR=}=M|QfaiX!50x>FVncb}afAbw6LKb}6&fERfanR=cT_FSW6YtgFZ=3Uf z3VkY+4>B3lqZclAmKLIqH7N6$pPsVN_xq>M9gC3#B&zsl|EQg+5cWN*?9~8zZO~5U zS7hfAH9&TBvXYAJY~QK^cu@K)wM6zjssqp$c2apn4WLx|o@}BVvw%ba@`zM9#v$>n zEpNQ&B;bt^`S)e_?kS)Oc4SiJQdxNHm)T}@2}74KS$cTHcYq3%Jg$N*EbH$Dz`j>f znrF{zr_=`j9RU#R2-WR-6i5Q^qmN=IQZM`bFaeG%!0N?gKMb}Y@^*--1WG$rjCsh^ zqJzlBEsH<~MLJn~Rui!2_I)QPM+kL9X|i!2p8{rH#-A~G0a#Ul&c`FqwsOSlAhPjN zB=Zb(chah{G5GAb#lXI@RmQy<-s&-AjL-kE!b(I15&PtteUQQS5s){t6URD)enfQSUDAIjWTC}mXFyfcRwx=uxs*-;W31T5%Q zU88YT5@dFx_eT}LJLOEg7%LQXDqyepvJR?OZw$PitpJw5RnmCxal9^~LUz9U10`a# UP{|Ze;s5{u07*qoM6N<$f?@!a9smFU literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_18.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_18.png new file mode 100644 index 0000000000000000000000000000000000000000..e1df3ea495e94ea5d0336d3aba41f02af8dcca5c GIT binary patch literal 1907 zcmV-(2aNcMP)v^AdP zHO4r`7~?pOfq1=Mv|aVRUauc=$8r28Yu_tv5tLp#fqLzHvOTCXomrzY=NMzWePed$ z9)2UfE!qIestw)+rsEk-(1D#v_1VEkEml!dZ3v@y_HfXXufmy;KjRD?hv}ZvJL;@N zWF*53SWS=7Txa9V$dC53^ zkh68p#@WQrf6k2fN{M;12%QCPRHZqV5vmGbfioh$dd^pufj4^QPS|FYBlzz~9KVIL zBK~eLJ>T|&rKlO82m4f~%0lPnaVG8<@iV+3+n>ir5i~WR0!HXC!oO{7!x<63OD~)+ zv&W2+d|0%e36|===?u2^w~WssoXwLNw@RWBAM~(YU|9hBcdxmE)eNwLYE-k#%rb4& zS;m0(0C+_);aMYLUA!ak)^fG+BfZp_vC^uDr<&)VU5?@oX44#ctDhq}z}dc8eAD<@ zaCFL$$ye7XJ3yp(Hbqt|E1q7Fujr!mx9U@<4M~v!D28h1fbBO~eU>(B4 z+sU5KuJyZ|6?KlD(Y{vnWMj6L01r&BOqon+lkp#1L(SpaSB<~hVOKH@BY7Psy(9w| z*kRglMRdHPHV4~47vD1e?u?UVhYXix0Jfk4Dvr^c$zxxX6|S!Nvs}YF;EFRU2eaR& zJHQzHuZH_RRM^_>6UqB=%J3}X+}R1v1fInu4qyxW^dD`Mk;W|QtMi!r6~@PCt3I=} zcQ}cybD0C!qN}Nm8HbJcZ9Y4o1D+Lu-H6A1p)OH|vwmE=f=eA>4DJNgL&uG&jj}q5 zYncpV)w9t*6Y*X@HJ6uBgqf9B*8ijL*j4D7h>XelDu~9YJ{I*WWnjkm(L74$NEYSQ zxG}!y0Au74T_JyL&IruOSo)vg1iJ}lWiLv1rQ478Z#uvj{O<_(-%OTaHe;~$IvJsB z^loNhhF!TqpblSm07EAmL^#V4A|sw{e3hwGNy*y$^KufXpi*!|l)S8=I>tkh(#*)J zeMj2Qh+SvyNT=Im07FD*BBG;GV1*c}lwXnAZTv2QRBdG)@8$qw)D6zs6&S~0-*HUj z2s?~FYwW7d+4x&JfFWYGS%i8pXQ?=VAFtM{8ZX=DtP`j+sXFRyH~@pyaAqKESM?s- zkWgjDH(47S5wni*I~-yK8DF_|20&z`fsr;Qv+Gc+Wg*(nY^}%rq8?0!&i5n-FmxQj zxBEV3z!_el=26C9A&walW%@BZHUl8CL$>b-RZ`TPnKN|j^(=9$?gjV6@CXi&p~{4@ zk9{BG|GI1+lgkcMt&fheVtlrjtjs9b*hf2nK}CRy^6uOnN3eb`JDc{E6XAN<{-X@> zcn44h!AOrvLIqVv@N!;uCh})9gBs8F|9A&bX&d|T`^tKi^1>V;Dg$aytK1;EUHobi zh=|g$^>-X3BXyZPuF3dFHYe_j^<_@**bIP7Uqz-*!PqwocIcIQj3uN}^HKMz{?&~0 zNC!aU+reb)e@6*m##e1BJFyIqMQY{tg8hn!dbvkBfFX(?l-mIn`H@`a2-$7H&&Sqd zWw3H9`c>D!F=95n1FF_Ww*mjGIs#?{l#NKE*D0FkS8xD^U6GFH8lNE>%Q6D49bFf3 zu82cCo&$8Tk{Po144Koh+d?#sm6z(Z(XXj)Iamfx{l}qqKz4mneT?B(Yi%^I`W@X; zD(?bNFLlMmv5#~BtZ}MerCF0vh*&zVvkFE8RevReu-j0SF&Sc!nq5-Psr``>8 z=1~E_WZri%Y!#KrjOu8$4IQb=C05QAGujRki+eJ>JKp(pWP6QLZk6>%b61HcM(_%v zTg4cEOF(uoD=%4|>Rd>?loNDP^3}-7qc(gxt zWvrH`U0_#QkB{FNs~1-oaRre9l^n{mt5)>%WA1!D(G}Bl|FDhh@W^i*Om#gKjTPfp zGXT>odS|h^rwHnu$QX_Uq9QvO=-ptXDvOHB)6c2aLUhmajM9KQyjQ)O;ZAAM--VUo zz3hw=Fep~v)qTe~vX?;rZUH+Ky$igt(ddIg)ezONMQE`M|H7^ t;=8Yw(My>Xqs=%$RX!^(yE6c;^9M>+T{RO3Ci(yX002ovPDHLkV1g1DuGjzo literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_19.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_19.png new file mode 100644 index 0000000000000000000000000000000000000000..d231a656181d21d77dfc168ace0e42aaffd02137 GIT binary patch literal 1974 zcmV;n2TAyeP) zcK2Vx*@Bo{$ALSO;10T1elUHs?`5*Rn%T>D0(j+UaVq#8olLwk304OGh`(&F5m714 zY%6^x`x8yBjIrQnV`{-yGQrAPztX1+m7ub6Qo&~YA1y4RtH`m6O~aXG;cmK*e2SiX zRG7&7Sx$ffJwP|hj!@E*lHd$fgJkIXtC~tL_v$!eikNAU{=V;0&YpSa(8-Q}2xjjS zg3lT}gzb$z?=V#a-0v3#p<;m1;>tuYd)>vcIX@-%Q8JpZQ7l&YOBr`GN`P`Injmwg zQX1aQPWpFu@GJh<8d28&HkqoOsAQY$iy5zil>}U{vX?OeqQeB$&AR*KcjsH>x8I)^ z4tAkR0!~;-1U8O#D!l=ofIEWUO~R_p6?VK|?;haj!m}i>1w=us^as^N&jf!Zx=CoV zxCXS@DI*a~@0E+z(V=Kn=PPA_(W)Bn1b_AEKf*kfGMF(T)AjbZZ5uzU7mpKUPO-W1 zMA&b3Qf6s>b?{gDQJqIUtLXpocmHe6E3ev&s#Dp#DoE(_-6!AswZb0^cGjcdzDK3g z#@>Gyz$n(E^W0C=&2F^ie=8be3w+wiKdTpsug2O=lef=RwSPsepT&yg^;n(& z29*TpfFE0(2#PJdjSg1OeYQT;OJTo-C03PO=7X1gUjxsADhW8|okh6{lr2X4M|y#k zbYJxs*O>Ja*}nbKJv#vmY$F(DGuhchz^rE*+X>bc!Ds8p)>AEQOy{x$@D8YFW8}5D zOWSI5x{Pq=$&c36(WN?9CcqfAw^<5V@-SIe`yzIkZSYnFzspvKf`2sw7&5A>=qY`* z5m^tCF~Us4r`9lIM>TU@TemX+qDuXlKH8W`1eIW`g3o-P4%|Um`&{-SXclbqJISB| zs%VkTV;jPJsnYz)liw)==&ypbe>Vd#RO(r#Uo8!0Z>B6LyDO8x+sl}y(ieOj129wq z9Lcd08Z}BtpY|P3nM#7p_R*e#CG=62G@GZr2|N=K#e3N1RckXQf+`K2fMAkzPClEb z3Z-l7v3VYu00ti@47NSTWT|W@O9XGz%b-7KBV&+=_Rp@)`!4=Hz*C^IoHcQNlcOLi zJ6)_i@f}&V_6Uz<0Bpn*)kmemGeiX)COPB8M~y1GEmZJG2EgFshTw^>pvnqedz~)7 z>tocIR+-?D31DEsXXB{jfr+FNAxaP&!@wR1z6vU{i!xF286KSg9=H)6SQ40?qT`5d zsy>;`YVb40h~)e_v*3^M;2wY>qHljf*hZl&21)6o4(h78W`d78-Q-|Q@l^@HU;*(B zpQ22rYoFLKs+)#-p3UX$%rbySwE_Lg1i&j_cD1_8zcKpn2@oo|s`eh)14O4{j9RU} zEBJoy&L`>_SQCuDBfF1GfHCrVnw^+V@L8f^V;MciG2bUtgWvVn!R!3Uyn_I+3Q#&qvpXR=z`HSYeuWVM?X3x@1I-Aepey9 z0M#p(m-U#X;K&y?M>anuP;|XSyGrN%>>CrH60~mc*?0CEZJ<9H)2Q*R@$KmN-(PzT zJQ94gHADMd-=fYwD-EizVT~lN=PMIH!FR(3`##gvcbDUFDN!P1tb%fttEjBa;14E21ePc&N&XiMz#1tW_ra)apa-7jYRSMLt7Jhx{W$(H znWzu)V_%&BjPfzKi~(lv;HKN@8>*$InvB)k!B;ndW9T}H!S$aiDZI@pvPRU)RduV0 zrFsR{_HgL`# zKiGZwaW$ga7`-WDa!N1zT(O48&dRx1PvgID+u#2yST#Iq!)G1r=tcEg$y9=c>iaz|5hhKl$4YKm;t;u&pNk-*{jI0 z=c|BwjK9m*z*(mhovUCUX~HV>+nFm1mPb`STT?bq2bBZ;2XF0HlYkc%w*UYD07*qo IM6N<$g8wtl{r~^~ literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_2.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_2.png new file mode 100644 index 0000000000000000000000000000000000000000..e2a864c76259bfec69678932d7d9321cf8279f41 GIT binary patch literal 1636 zcmV-q2AlbbP)g@s|R= z96tm2ay+sV?wac~Mw|pjog^ey%l9aWW8lf$UGts9h`o%K#})FW4d9cMf5P%MZ-2~q zJ%*K+l<&$Y@L-x4S21@LB4bDQ^}Jdu)g-!7zF`sgZOWH86^QPmh>(evSIgHe0e3?DI831A~v%%Te?d&esZ7KLx8-k?wutHWwNHdO7nYj$I;hqI55T!97`6AjY z(t)J$=utjHKtdK$ats^pks_^V#VB@0Cy-J8PBqn0N~yCtT0253NZv1nGe$knYb)ze zzng3xmhyYQaAE6*UBD=bRV3PbwosgjmlR+z(8ADFN|s*97GT~w46O*7m&o&1$<8WN zpM8KGy|h)}=RIpJMmbh`@WwEqT}Rka$U3VYpMD*@60D%SuzUX2MW^oUwbTI29EM*8 zh(@n5Q3lWxT33MW$y+Cn>y`F!LV`_{Hu57Vu466Ywj~Ox6n%km$JzpDvhV0hq8bXh`Glm&J zMi{6fW(+54pEBvlG6IkGRf=Bmu7LU;Kw>mAJx4un4X-;VpKA|~P82J#f~IKzvo_tj zu9vU%nC!ax{luzJ-;)MMu45WNW})cCOzXOGeJf?4=1kA}D3Xkzqrn)mm+m~Cz402| zHNea;#dy5eVaui$#{0EFtWJrooj+s<+jatx=a(|4t%{7mGb)racEs=qAO)698PS_Z zd5>+#j6!5wks(Gc+ntV%wbph6U~>?fhkje0*xHGUP6B9-x3<+zj(Cjt>_KnZqYXfN zJi12nncq?CHj@GvT&3|yvp_UZ)}u9yG5tMbpN6`g|gcx%jP8AMLm6ak_|J&X5_Eq8>~XYjl} zN)gujtzaVZ%U8h}<+G6jZRGBXF9m;hXr(l!A!Qj%Yk|n7jQW>pS^xcZXbc!N4wr0#M1zJJ^v&wnfeyR>to(Zx|(*@;9lMZ zwB&X@|77GFAZ215{br-L8CR=%8|Zod`P?FIJ>MB46=Vq>8OBVsrW)!LU=bO;v1kJ$ z=*?`jSog9{(&ELfIBCH?fW(N<-mBoA`8ymzkqoVd7@FG))5)a)$blZy9=tTi&qk2Z>!jhMIQA@q8Gwq9VOrI%uR8*CEHS}%P7 zPx<=18ExLG9lZX6rW*-BkJEJYzFNG#CG?)O7dZT=4-D2zvWUt4sK5sbWMgsAsyJ-1|opk>0&L-c!62NeMr2E6-T zZl4_ykn$r#Kwhf%faY2IMRc;tpY0rUAAn&V2?XWn9X#I}i;Pg;XCuXlEKe)0>F)s| z0iw+_SZNH}>pi}8B=W{Zm=Pg+uGBYy-e#;^#0momCz~EJd>@DXC*hiJd5xZ)CIPwMp$&Cj`p z_V`xiBhN?jLXNa50wDdJ*Q1pG|6M$5os#($Z~jCuk*ziQ&BoIJN{P?E==ryURqT%P idochDsL1)@Gw=^8Tzpq-BiuUx00006ui^S0SMv@ZIY+1iQh{FHgS z_i(lU3E&YKn<2s&Um-z-0F|KIgS#W}7Jg6a8LC9i?D{pP2;iMOr3n6gc6d(@KJrt+ z46#-GiJVk!;8;{;;flk|9<%$T;3GdHjI;G~cJ8hB&J_R+&JZ~;lNO@qcAcjNU-b*k z@y~|eRh!Z0>$>YB{%A|@X1%Eaj zq5UA+=!|C0%;GC^AaZEDXNV5p+f@rg$)B+SKPbxM*&-1cb`zmm zWuL%~;74iq-*mnpd41z9b^kCiZFxU zy7|5$uLRwy>~G^o5y%`vH+DA>W?^sQs;vww1>f+E`RC7OCjD0T{>7xoe)jLsW>(vo z83i~&rVKMdR|13b{?4?(e4yV0FgDtNGgfEa02-&>iflacbq7{+{8QkGaCP&EwI-EY z9uXlb{7ztZEpSKhz2d4J0g4Uk?tWb44lJU;RpkgR?*D!oC)PS0d<1j>l{GUZzAo_l z09A&ay5%b2GW$D7aF^^eU)hC3Yx{BOUc3UZfU@_|V%bI*DhHSacvow9NAMLWK2+?$ z6u=x)Zdd-=P4i{71^f zZo_q5vJ#vMel@K`Hqi5IZSO-$fNDNoMYges3^phzxRwNCJR`$ukfQyq+MPXrdrnjV z&~5r{WOaxiH#WzJVV_lQWVMDss04p?4Tf(-=)Lz7h1_YVIS|c>>XsA1_v6*H!g4=b zd&b`{e;{uG+n6u*?D$=Zu;MGTH+$PxG1Ub;0seLjumVj{1Xk~yEc_ySjLd9KL{hfK zw%-Z76G$3a;fD^<7C}A`h$N?S{#cVCQY^m)+AkY#@k#;=uwXMqK=W-t*g;p*09t=V zNm#1#zS*&3KZqO_uO@(nCqpG)dzJ8HuwxVwpxj;!z7L!aCM)v1x}mYw{>KoYHT@r| zA}RGGV(Xy8R0_$+uJ^H8@mt%TK+Kgy)p$>q-2f&V3WM2t>W+$5y z;o}rwKsnS*;_W!KXhekW+I zgg4g!6|meHwP~yJ>({lmvfwNGVE$${>{$6Xg5HYgQ2ovJx5IW2XpFLUrCVTrp2SC{ z0NeJl9O{Fkk7w;1dbZMrv2jYB5v`H=<>%Y+AE^Kc zND;DLUbU&_?x-tZt*QNtND>vY$d2FJKS2PL3RZ)U))@1Zaei#p3bOAN*!LNc9Xsx$ z31Dx%{k%K)cD?F&uSoW}S}UMb6wM!Vu1ol}@HZklC{+Bh+f{}C?!Z5{zA;}j5+EDM zkL>1uWE+^ZeD+;*K&w6|t)=3-wS`El_<-8jkE;RHmJcaHr2>zjkZ7h@v_#G7fXEk? z@*b-IN>J1Tjpjr}6atd-ih_70h+5ESzOn}M&(41=0V1%#qkPFKZ8V;>PYhn_t0Z8y zqV_GT1ALmvQqHSV0FrtunM%84$Jys<8^>&pxl#RL$Dw_pF^WC*&f2hl?E6;`fCV0n zV_%H;x&DCF3fp35@o3ksd=J3vpw<_Sdo%&E;?4uLVZNYZH{UCOsst6kyl)8BkEm;? zfOS5tJv;?4sb@ekk7O_UnbiTa!Kjj0EeaL*OJL9D(FAC%b`Vh^rxt!y1yCi~`1lW8D2s?ux6@e(| ziXxz1JloR=Rj})CCxFc_)g0+DJ9kI$vqCK*8}bMJRQ9|>0g#PB#2^2^00xzbJ6aZB zyjAk;uHZ+(WL*TCm)VWpuU;Z=!>{p$`c8yuwY$sd3JK6nJE;IGq)`=QrvlhwaQyv0 XJs`E4X;N8O00000NkvXXu0mjf8}P7( literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_21.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_21.png new file mode 100644 index 0000000000000000000000000000000000000000..0d407de64bfc2072706a182f61cf9c0aa101cd6a GIT binary patch literal 1894 zcmV-s2buVZP)lgDWXM^mm@PS!#j4`(H9{@y- z00QIS-GXoBC@>%!_E}Xb0QjJd+C@AAo~|7~^3aZuBQw9VpUR%AfcYm{C|hjb_n(b; z^lu%zd+@d2M+YC-?PUCnd@{oIb6x%<@wq70q|f~SYZq?fp=_KOck zX8c`5{De&)YVI@`>_Sn7MvbB#li%98CuY80hY5bR&raWv?N7_sHPAYzjn6Pb)E{`x zGJ3Oe*NjK&Wo+01NeBQD4+zMhZ7Q?1JUzSSQ9zJ&uL?fOaF1!Tbvmp`0l+$DDb6z* z9ZWPA(dp4W!7KyJ2%FWYxwiHh5a>DXi=fP5+aF{GtH?wEJEAwxd$=O_kzd|EZNRnv z^4&JpX#Fw9*!GDXpyrJc54{nfY$mKe{40Z>om-_0i9Ty%3IKZHDhNbSlj8xw13@Tu+DiKL6UX23=m}eY!IxLtn05dqAU=W0U+8yBnaK?+IIa; zaPAa*#C)hkvi>nixbM!3ppGEJ)#lJ^Sfr_mkZlicTVGy|~0Fon%(tD~90 z(jQ`k6=h+CT-kFVU&i?VEKUPJ-9Jbgs3dsHS_JhqIGBF$Ie+Lpej)f&S>5n zW6OePx9Wd2<55C*tPqvHs1$tpc~=0490>&PfV)SsveC@;fqo+}Wq`gt07NQ4$T9|H zzt!#1?5bM^3NqRY(zW{DyfGdG0Fev`Sq+Uk>+H6`__nga%o;+rl-T|Ldj2#3h`1Xf z8>umHqlo5ZL5uWf8%&SZyEh2y!?HgNI$NUVh;8I-+Kozz zwxgd}{l@}ej5Qz_BL;%j=}>N$_A@4{tQ|4NqX94m4+3;RDAV;^IVc+lbl~Xssvd&X zMdO|?^7(iGh)BSqI%sK82idNLbfP}Nu3yPcq@UGwuOxXkytOZV6SzW{0CxLayN-O< zW1e)Hvgngx2djt9;Z+P^>!i(SogpZIsJZg&$lOkY8I3c+pApLxuVa8Q;x}XHxy_J@ zuxyg)v6-)R^*$o8<2Fft+1R`Mc(K?_N7NjF0L_VNJWKs(4)UA*v~%tH5mPV?@__Al9>#(Jp-a$uXN}+9(9XeC-@ndsv>h=2Y@3) zvjQpw%(&KLgOBDRzdX?E`AA;D08#xz6z}~$L#mnIWd?7)=xcc_0Bk3ZvO|CObk77r z#00FK2Ldb1?PA+b{7a#$1$FLrJi50toxdLUZUx?4=7y2^$Gi`SZYLB7o(OIhqnO&zk?*XE@-m@(DXdf&)K~VfP0EpPk zXYSK8N5xWj7JTGu27;(OJpM({j8w8Y>jk2Kc-KSy+m1uJPMSt*-=lr~`%eHMYVN#o zq?=J~=7ZKp!L_zLmdY5Q(nGus09mk+el#B4v8(fSKs?ZS!D6nB+9nD<(t8~MX0lSR zfifz)`c-|4SO@_jdKX~lGQl6?g$%%mcerTW)?_U!`ezHS2ng(zl@0#3{jom_&~-Jd z>r8MXDz|#kEkm#4*+uH`jaR$$WbDnEA;59mU>g?B}*M|14k@t<^(gf|2R54A22VCQ$>LW&bR=G8T3J z=g>%OqcYzr4#AM{-0Ux+z_&U=u6Jpcdz07*qoM6N<$f_-9@Gynhq literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_22.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_22.png new file mode 100644 index 0000000000000000000000000000000000000000..f53ee0588351daa326d75d7f83454511592676a1 GIT binary patch literal 1923 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 sFcLjT zda;iÎ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 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_28.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_28.png new file mode 100644 index 0000000000000000000000000000000000000000..b16dda91d5811ca36993ea8783a19934068ea27c GIT binary patch literal 1969 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 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_30.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_30.png new file mode 100644 index 0000000000000000000000000000000000000000..08074849841151bf7e31c917e604a6f103c05bca GIT binary patch literal 2028 zcmV-P)t2Cq)Mc?8rJO4lgBX zuQ}%&V~p#%#{b)I=(hDfd$s0VZDWkm+!YzR5n03P!=A}@PnS!FV+`2Fo;^&diLjY# z6sJf(P5y6zcI1WU&O{y}MsUjG-w_E;V(medqZX(%#GZyfY&F23WewK&DzfKAi$Q1tKf!z;B2M zULo3rtYIMH7fPQ4WQ@Qvh6({|{ZBg@Mo%Lr!BU8|_G1mSI!T421?0W^i9J;jHN+>{2!hV{6{RBM>BJoo0Flp%<7i!!NtK-uX3qKbWss!+Rtr?CYt+Ac zQ{6{FDQARycFNHwBXm+i`-%3ALY|@?NFknbqMl^6oh-;Q1u8Q_M!NJ~?U`&ZRq~<{ zA`29s7 zk!RkT)^ivEJVYV{6ZDQMUCLQC0=ADG;-yUNy_}oP*_jfadc(T}$T28i-bKDdN4Vc5 zK8sWHO3XRGBEWicVu3MUKR*6+@}tG<37p`;TIZpw*(xlBu&|d2!#k*wFVlx^i>|A& z=36f`*JZ5y3JtFWgs2Mo%66;p>r96l*95H*A(&Ts-n!$>)v@e^6Dj&UL<&VDi(aEc zmZ+R^UYY{f0QuZ2p4hxB}1WkWR7dPP*! zQ!|F+DOLAHd$FQemiP>56*9XcfP|dyu^KdSQUH{vn0IA`h~~RtxmIfNBKr5UIE$8$zcNM!sIBLSlx9lir(wNB$V#yMPF}UF1t4vjv`9 z-wO8@@hl2>1X|BOg?tSrODO`#2`wWTBTjInc0g%L8$s0LQQe~D_4Y3NTYap4rw}#7 z2P2;;a^1_9Tu}E}ZJ857cB6>wOpe#cj6u2DGByicMiM1|&dI+Gtb}*H_&X5I@yy6~ z)|GQQWWx@7W-Aff&^2Y!*fYn(}p2_W9 z$Ql!qBU_(jQXs9s}8D0%PXC@N zu9JL}wyYy7bBf4O`1{YpBSz3kTBpKT7(~^+hj)`7ktcGZiKY+ub+A5Hzq@)xSBXgI z-}!98n(OX@kLgSrLgX`mb)`QGM~iiaey@0ncw*#8XubF3^x8j#{D>p1e%jHW$m35z zp1;vC5Z$wW8F@3t+jX+A_P2|OaUyw8l>hOA5Hx^2uR?}V`I67|=>UyqXL__w#=ub> zvHST!hyJ`{XJlW<2p+nFR@@0xk2SKNme;EID@AP7&={;J7F}Dv_tK^}7t+T|4WK7J zbquVKU0I`Q1XfBqo%bU$M#*PI{f`KM^3^Ht?}DcQS!-m-M`>i;qi5E96+^M=4J$RG zzG&aD2Jkk5gzQEnk7dC&?a3j>=txj0LbEcn(~b6G`C@Z;*N2=~TQw?((0$j&rP8AY zA(f>qUH6Gb0G5O0J-Z_LqR>1b*;!G`jNQ9lUt{buH8TkPTngNU=+TC)?J3Y|)Au{@ z3b`(wWyqg%zW$FODWvoU-KP6@g>a-G_Npqwg6x;^{A^^{0ZTtw@~`Xq`L}^61hK^} zi|*Q>H6N103!QRK6amoM6{BYBq4}bQSs^!710btso6`!E&pN=Oi;grX+{-zT=X=JD za;Y2_xmxpNpo_i}*9TLkhwl)Q93M>=5kr)7N}05bmIosFWIsfLZfDO?e-C$%{t^Kq zAs-=|=OUpU&ClAA0WuOQH2|8o>iLoV-bK2+nm-BCf-!+38>^0u$Y+hs7(rHfQjSO@ z$Qa*U*O&hfpcN~Mx0r{h~Qi zdY6_F^~)GRBz;&O{~L|qi4?ENVR_Bkgq}w$nHfU_(x{>#{d5G7`>v9&WxnJ3(2Gmu zYUOAFkpeZTXdVT{2++0000< KMNUMnLSTZsm)8OS literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_31.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_31.png new file mode 100644 index 0000000000000000000000000000000000000000..d4dfbce33f3b5c7aa34e16d5b3b7c855a3741c71 GIT binary patch literal 1922 zcmV-|2YvX7P)4V~^Od12cB9Hb(8_J~C};t>w-vQVzggS?nVH z1o^Y}&w?QyA?*N}Nf;;C74c6f!A^Uuz044g=1V)k43H5gNPn{uWX3HePrQdq=Y&-l z_3#}|Ajdz2oeI!e3;WhusWo5T!_`iq(KkWj z^8U=YD^iGC1E7hc=Q5|yc&Nl`MPSyl!sZ?GWQq42E$skI6j>FkbcPuMRylzjYX_pW zWz;CUPgYTl+Fgt>oix2+vX3QkdQ7Y0AAxkJH>Ck9O-Y+~LzAvKusFKq0|{h2iXgN= zJ?To!D!|H<0ZK2Yh?jO`a9bXNHij+4x>45H$na6jIKeLRyIo#euZ?bxFhhLD%@|@y zIU}z~ZdXUeY&saRCt9~|EA5=c3gSE57eR>lY>w3iuasVG+iCLq=Wc^;r|)Oxjq0)$ zxLL16i^y!Mj)ZS?f{ff}@9TLyWXAB?-ce<2J)5bnS4LuXd{nDM7?Jxd*nVugUgJb6 zb)${(NMYsQ8e=EJ`X=&A z;S0_yOMZtYjagWRgjr}Mo4NM!tYVg3d#2q<+#>`;vVyR?K(p-ZM2#weUN2Kvd24?g zZoS}H0<0P$lK(dqhN!?BCH@WYY`;$~EJON}-&<+tNl4r8RSSsZALV5EOe+R6 z9)nTxy?ft+$X@CzVVW>cp7n&fEjn`P`63{xj{102zaINE@jK^$d^PYyZ-U-%Ytyo% z&dO-kajf>JRzZC<*m@;ugPzaSLTJ76v#9{G5la$NK?%qqbJeK`8gx;UW!81y>&9t^Lq2W9abu~+T8Mkbq2N&Rqzb?45^tu z(gy2iWXmY=Pn-fWX;rrI`dz(~cMP+tbff@sT*t@n0xTs!N4v;byrb4AvQ8lHbvxue z%ch8U8HL{hWUKkR0A`alv0kPBB#=sZ>7o>0AuNzjydip5!AoP_Dd8lt3OtKGhxvT~%fr}|ASdYecWmqm6|nOA z6Vb2LR#*2cfa z#xN@{dl4!NIM4QuQI+%HDGs`>oZI?`;LU#_IgB<9Mb1n_Nn%ljj%@OrW!A2Y?cR}k zH?qgX*2I4gw;aJ+fJc7jyd4p1r5MJR%yT^-+a_|l-AXWvTGd|)wO;;skuKX>KR;br zkAOK^>UJ4*Iq3w^{{JX|^d#DZs{86-VWJY*Ajd=fBcRhsr~s#AP8x+aPu`QZL{2G&&sQ}v8XfOtu4cEk@qD3zPjS*ZzUKrVUkXJ7 z?SyyYV3lW;6EKCZ9?vTnvwP>gK+4o$DCd7DfaM)eAUd|NW6U~%B;U*NyI$^~n!q9u z*~XIJns^iV7RY1ePP;rO@gh&>^(fD09K=!{k3g$WhWuJ@q@T1T#^>YjmjltcHIDu5(glP=|Lwa54IGmbF2;W`+s;9#!aI9Yq7T|2HHe=FEB zlv%*;yuZ`QBv6s%-AB)@&zbp8T*Fge(!q|24O1%i` z&-F$z{dPdkC+*7Gq}ydTPtMOML1fcu@_%Xo27069qIbiaN7o=;TUooH=b6px^Xuzq z4e*!(czFsfxc4~`{W7A^oLUtuN3bH-d(K9F)@eMPc7mbr1DuL{J-0<(p3IYm+kr(-uR=WGvhGpJFNhJ02l+#Rk^2=ZvX%Q07*qo IM6N<$g7b8%pa1{> literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_32.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_32.png new file mode 100644 index 0000000000000000000000000000000000000000..c9c169f2eb4b33cc403c054bc170d3880343f82c GIT binary patch literal 1900 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 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_34.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_34.png new file mode 100644 index 0000000000000000000000000000000000000000..d0f3a5383d809824126230e478a9e2ad74da83ff GIT binary patch literal 1923 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 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_36.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_36.png new file mode 100644 index 0000000000000000000000000000000000000000..4b34fe377c1b7ed112f6b453fbfd5ad4d004e4d5 GIT binary patch literal 1937 zcmV;C2X6R@P)JAWDFmT z{pkGLh3w{J>gaX?DgQ2X7~j(Qx-M!ivuBq9c2lQS5dKE`myl~|24Wd$)nTRcdu!d6 z0$3x+3RTYgElyB196OI4H(5e6pgx21i3njJ9pSe)L8h?Vecp2oYn|y3A9=H@4q)rRPm0Iu2cW^VgK`yfrF! zL)zqnqFCo~^xV5n;d)X1>Nxxr2KYZ1KVrLcjQocZEWKKE+kNm)w1zv_V`plzbag)n zvJ9Wiv6@A89NrVg@7#waYh?}1?#MPLx{09kedSOk_3m;4R==tdcNCI4jIV*%d5kg6 zXhZ1PN_D+rgp8vy&LGD{>;ASb0@)0WIjw{7jKb1Cl2Ks{xo&3T6-My%l=7b_Aer;9 z(zZ44%os#2l4Sry|K8zS8;oEXYb8A(r@9+nFwOVYJPAGiivcnU>1!k-8+k|;V*t%! z+Mz1OM~Bbqb2lR|sW-e*A}|lreK}p7$=yr82LNSEjo|RwWh4IOK3#@ zC@*)d&B(LTf!Fy+r;+z|ppuHKko%#&4%P}q)xI99smgm^1#@V~QJ9n^b=?8I?v6FB zbA}%UTZf5qxt=G-T1B0gW3A^qz_36!TUqcNxWfr7{h!uNBN9lM1ws zT5mMwPHL7qbjsB7%`bzPDE0EyN<>?R+!2XZH{$7Y7eg_va1~R=N8gZF{gR4V?UR=l zv;tXr&E)xL3=6CE(q|&aTGuYjbJi~wQlHPf;d!~f=T)q_a*hf{Z;yy@jF;qDs0N35bOvS*Qq=p95HX()TKnbr%z4f!2rL21d@nI*a8f znfkzUFjT#>k?bKVNYUS{aqn~jrVuy34P+v0UcEwal@6nb)l3srz3lpI>XPa4=?Ir# zj6Vj!0Eo)1>KsL(XMDyO9s}s~!nCT|&BZvc~U(?n>l+PnXOYSP_RD&pIbIYCU8ke?I@} z0vMY1s#>`j)DC8i-$|*ulbAqhOU_xX8?xO*1&r|#8-A+AStdoSMm{ne>lkc=BL=iO z7bFKowv@ZGHeij9^f)WVmjW%CTZw#&HnWGwv~N?cS1VME|3onu86Uy?JwO!U*7F@X zzjC0=cvSRSwE~)po_82Oa=gsgNT0vH4D#ARRxqN^3@kQ@T2F5-vle=mZSA@vKcaTF zt#zOOd(D3u=qX$^{+!Ef!ZJFN$2dVWH%bl68CALfrhCZ*sK(E~hi8p%(R`=zJ$aoi zrB^6wCa4;}iYW4}^JfG0Ck0qWX9VtweCwHh?jcGAndf&K-_mD7x2udk+Q#P3!u4WW zFglc7(byq(1(uV%#rRAcILGNg|LBc*RX-9opRE|Flg<&kD)Wqt862p9T?K0+tq)@P zzkU#cCRoqAB7V2=8B~qS&gnR-sO^k&vFf{z9)OAot9o7C9Lizrylg}>2CG!@jI8YW zpkPG$v7Lw1>5BpM0A1-uMN$<}TjfDU;GH@6F34bvic=3(i}}R>9=+=ctA(F7+MJ)I z)#{v8==Hq)SM-WnZ+6d!?$P~^oPZQT@2eZr4%1cf-|Ykv-RoLWtFK;>X%&2C4PX^w zY=^*ZEHeHIqLkpV)#|?FbwxI^gJ(cACu98MIR5@UfZmi=paY%V11gHLwZZDXv>{g3 z@E9?=&i5JPU)N>-9$;5n)+N_VN!k&lk@TypJ!1^i1B7tPUgT%w-+BG|?_le1OW`hb$y#*;7Kj1n z)nft=cN_nQ0W4)$bg@9ELwSx+&BwCys4@Yw#v=@Xlwl7hJEyu<1=A7aYu>Nu;6;3N zW#zwu0kV+Mv0~6C>j`UZCgSCM>#!NTh5<5|8<(4`Fi3Xp4xm~{?+Y1SqRIeI)Byhg XB{?Fy!d-=500000NkvXXu0mjf&_JrU literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_37.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_37.png new file mode 100644 index 0000000000000000000000000000000000000000..4935b75a6f35f2c11093d8cee1a0e9991e2a1bf7 GIT binary patch literal 1944 zcmV;J2WR++P)NS!%o*lQ%)q(yt(Y)&5mv#78JQKt+k-1iK>sj!dw_o@ftOh#x3BzzW!+uOR)&nV^aa z@!8n7ufJWWF3y&YZYQwvuR;g;%;xhvrMb$Q!wj%Hb+U%=8`Hmq)#Wpgnvqr=);fQr z>#`D{l3+VjJMUYZV3s&_o;q%137-M|9(?YI5Czr|zQqYDjot439y*ww;Sg{8u&WPH z>TV??cu(%=3A*tl@{dF3@|})w$b?$Y8%A_&y7lI#HHJ?kzk;#@D4u2CBWGA4pvwuY ztSj(D@{i-k0Wwl;9rn-ty|3LC))`hd!#dQH%D__*od!O30Gi|{vIxqWjUC>VG;me&^x;Dy`9& zXx?XrkeLjC(!WANwqT}bj9+mE*4Q%pb|MO<$QHJT5zvaD{I_aBeKYk^s;o! zY(dU7(-_`OdREJkZOZ<9u54;L(mtxe(HyIX-LrJgoEhDBAPc-sT|?HVOK6ttcKm0T>a|YE}x*{QpxNJ@}yLi&G z(~h01;7TV@8u6(NUpIm#d+Yf1W4*G*Hb15i;@>vZ5XX*^A)U!ANDcRvT4y4ZETASn&G* zQB$WXvk}T7Mv<41sy3pC)Xa|T9g>li1-4IW)JCX8{&@dS50EuHR(RH&p@xddyaKGQ zBQkBDfieb@kDgtzUWI&Arrxu)vsxl%$-kFIni%uY3_SLmNBOlH=iG@mpM;*F1sUloel0w6 z0)_k;;!*UoF5X8Eo2%$zU{QxJsE?L3Qnw=KMU*za@Z?t_tjEd@9b=d8Eu7gdJz?n5)3-i24ja-*QU77Vedy z&KISpF7j9FpB<-U0rmY8$ybhnW1J84k0(89ikPtRepfVJd6Yt6aj?bv9tEuU{p>p42V0J0T8*&2{OYfi?oLN zXW7Ek)VB-10Y;dyEj#+EeF#eT==s}DK!%|EmFV}RS;J;h@g1G`Z04%SN1eUjcNUDS z;iEkOtHaEY8Tj&o^s#3du66>i+g?4YrOnHV2t;!#*TIlZ?Sm~?Upj@k%CAB33C?0!f^JQ(Y z@KMiDDHDDk>(Hafua=}M$Uo2X_s78&na4gUYcNN=!Z|xLz*VIG$^cfmH>R=ycf+4D zX69$GM55Yn$ISEqSCfC9C;v~xRO{y|x@4_7f&%LZ=<45pMFv2|sOZW9oemW_!b(GC zf49$-YemoP8KAN;=zdm4H-;nFpYeRf1|Q*8#%vE@<=vhEs<5?jh0r_u38vfEenh&( eYzDZa2lx*Z!7Ci0000P)2x$ZqmI z)d0uhtC*zw-2pqw_pJzwGATunD(3!2d_ulf6zGGTJ&2=BawVclMVb5Gu%moWMWD2y zYeD2ZVx4zYertQm_pJ-aGKt{M%0IB1e8n~}!X*98+VrdZAM7Mwu?Fyn^W%x2Kx3xh zoAr!JV~bSpk>YK&e4!#RT3AG@*cH`&m2x8?wnF*zyj2)h%U9y7k1>X4od}Z>(-w1* z@}jveij0RK*ITqAhCd_Uv`m`tFvwC4!ekY5(*72o)hQ;*6Uxs{@`Y*u?FO_Qr7^VH z!!tlaY;;&N%L^*s3gQc(bE`&&xmeDZaX`>!iJph6I{&;(hL2V0YiE-lTVjuGMO>H=57TLeI{%JZdt5F?oJ8m)Mx z5g`-eDW4K%c&>^PQ||<>R=x+XP30eL-GSqNv?5Sio8fIIJX_Plo`$QHj)eS7QRq$D z5CfO?`Ltt1@N5l#5Ja)dO-jm(To+ltV(q74wt+KKEd;AN2V@;RqU&3;dCt^DRkMvO z9n%1;;-x}yk%5a9lD%;44V+NAo?tTytSG_}I@&!f`NNRj`{|QmtP03PPWqj%*{z^M zWGk)b1@SWyIuNhdX5mQ1oNcwdhbY?f3Jbp}k4M0D9G(MMLX3oHYhP(?#879wb(Qj~ z@_i-Bo&`j_%QGT+Z0%etAO@K2!83}Fw4W=Lo_#g~8$gv;ctw>J!Vw->CbsZvHlXVlV>^{C=^Y1_2t1-}6gZ63ZlZ|(xg*wK5} z3>Ce02iZP6-n|s2zF3-Ci1lQuM40Acp9jN z6gKI{GCDpSqMnBss5BVjw6*WMBb!FtE?@3IVwTf3p z1Zwo+JAqd!eP#%PMggg&iF&?wl%Vk@4UDpF911A{_TGQmKxy&HHjwT`Tf$jbU4j(> zH2%DZk&Oh_APS{{rVlI4pWX+c$E!m>HH204tq6cdhG-d0t)fwcOh^VN^lN>)w5EekDF7S{bFkMF1+KtKsE8t4Pf7Yzc$% zGjp^ejdib8_Ypb1M!}vJT>;BWkci>&?Foa@myX`LOwA$jhoD0FV~n3c5W4AXZnl)m z_tCEBf;>K+(R#w5yda+KosZTW5y#6aoy*}=1JILPaFkhX9SZGQOX*pf{9KjiSWckT z0N(Xh?I8U&%kLPpkW3d!04b-uwCg3Pyx!kw literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_39.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_39.png new file mode 100644 index 0000000000000000000000000000000000000000..d276c21233c76a9226e90ffb3065d2f9bfaa23af GIT binary patch literal 1662 zcmV-^27&pBP)|~@=aLw{BfrY{SWbZd^cvNX=m41TiX&KMVVANZ=!|?!pCYlmEm0!~V zFp)|}h$tBgy#qTVzSFs>&Nv-jv`e($F$it&q&CGFE?VmDqMZB~RPo!33%6ZWn)s8^v;dL}q;PUa*$j5u7`}Oe0=x_v@dHy&6 zUAV&$GW4p@74aUqR}9WIdYl~E=P?Fcnt`Rp%_|tUAyt537ve zePUi>2H=FL%nBMUnof801f9m$j9QU7vS51vZjp4YvSHMCNX}3J+J9t?uNhu5dUPL} z&b{fMJq2KRg<5q4YDlef?s5VuOQrFpy=CS0>e)*FShm+dt23!3+9O!cW93?rv+4{L zY2PxwXD{7g4L|oX#u$+IGJb|{6(Vwdm4Gq{1Zd42w?-35 zTBnr-aq|t4ukG2AxdNW3$M^q~0I%{b=F)R3opDsD*#>XL_*OaN`UD9P$KsyzWF|2K zWW7_{c(&$8l}fMeG=5}HniEt6qQv7%Pf*+hY64NAEMy!dS{8O1-)hV_e%_Kt_sP-c z-n)MxB#W;jM9q(vytL01XmtSUaoI?Y^5i0z%HlOXl>>iX z>7Ok=yU^wUE61V=WoX8ksht$)A%)I$c;b{6tWBFHhqWIgj2M@f@`1*Pg-9y7y{X zDYVl_6x_bwTa$Sh&3G1Bil~UG>`X0 z(|_cAUtu(FHmcMuruCHpR+^HPGw~hKkNM&sNgl1~>yF?q;{z}m0B@fA{8U)SLe7A9 zoMOC=lyNw2FPC>R=6QV*xM-IKRuxCS2zK@ZVg|^JO;1n%6Wl<^a~kT9VFz7pPbC@P zL~zHasLa)S^OV#op3-cC;>t$+$paAYxt$s$+Wcj(BXBs|Nc@&Ez=`n6hU-0NWDgz9 zajfSsPwIr#&}2*X0GyyF*MFKVP+)?>RqfJ;Gg^&txsn`Y7EKj1Pc*BS<|Gi{I|69!_Y6;Vm5U6YYG<(ef>R7XaRJEbA43}o zNza^&Zl`>TE-nDxxBzQfzdM?_`2)TF^fC2LeC7b! zIsYW%TiyDKj4O^qpS7lf713Y8*Y!Jrt3p=6!~dkN{w{q*_`1FgtVXvpd1|4D27um} zX)_Zqxb+?froBp*ulu`zyQ4pftP^MhF^sM(Lr-Dax(b`98K9EU9jM3z7HugDMCe4W zTk=Hte*R!YSK7bZfjXT)mX*jcB|8(px7@cCy z2TnyK`X?$JQ2bA#e$^4G(eXXPPX6qljr%_v|BiY5DpvUa1224YscsB!od5s;07*qo IM6N<$g381tfdBvi literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_4.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_4.png new file mode 100644 index 0000000000000000000000000000000000000000..354a96b6c5b40c54cf1fd55e0d7205040cdbf583 GIT binary patch literal 1618 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 TfiX(a00000NkvXXu0mjftQ1Sx literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_41.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_41.png new file mode 100644 index 0000000000000000000000000000000000000000..529f6cdd4554f19c211e1c06ee28370e31309452 GIT binary patch literal 1654 zcmV-+28sEJP)t^d=5qgAbU_ z)f@mY0071q;Ndt9u*TwZiZKQp$MJawKU?>r*KTC(id=DRBz@jJ`V8fGI;61x04EhD zIgnzE@e!aoTblqMzq|9PjU7QyX&=J#pM;a&=m-QYI(KzGwQt4FC=;yO2@qp&34a2B z3a3*1 z0H~14K$ux%YV;krbH{fEH(xVp4KH3LdWblL7kJt;E^{Xa=-%Oj!ONzafup341bL)VVi<`LPc)j&Hh{-8P#xI8+JGX+f_Z{7KHu6(``{S+O6z?tVy z0Pul#1VTn$6}onO#O@V`ONE|fhxP9<23(edwZbiGm^2|Nup+_G6$mKzF6Vpm&a#J> zM(8}LE|mc!V=7s}lEvxtj+&s;`Ib{Fm?I0Z29O46_bLlUONSN=72x$p*7=s>EvL`U z!&>tw{fnmnil|YmfxsPURnA>Oz-_5?zBae4-O+XS=%3nl3^F=HEweR(_dZ=*Z|AHA zLj~=7&X3Hc8=~WJE@OwN3P!)1H# zX>u$E_{h^zK$e=KLEurjhS_nuIp0eW5jiupmByMMSx{UAMh&uz(qNrdBI9>(eq{b3 z#|2o@s{Zk_+X<`yDqN+@=qW+dmvO!}m)Ut(&gZhIExeYguGw!1fJknW5M5x+@zV2I z=SPFio5#$Yc@T8swo?FI{0KB>db&^#l_S|=1pyz=ZOS5AS6M;G=eLSh2Jk9S4J!*R zu>q%7d``!C^j}5&QTy?;wGk=;;q0QAC!EjqOL>($kLOr!zhs~Fe0T7mxgv$nZ1iQF zUky&{Qe_=M1tVoqSqn(>z9I!shH5fKcL$7BU~$IK-nX99G2Xac@WlW;2xc6=>twmJ zwc}SL_j{0zdONNQwdu5~U_RIa&96J|egOaLTWO3nmOq!)uCijU0Jrh9jzU@vjSAld zk>-wef3?z|4T9`ZF#^d(kpUv-WbL}^?nm(59(6E(H-hZ$M>dtxRdpXgWq_IM8^CRq znnrgrSoiUp!t&9dQ$UsxehnRSn@y?G`%!qsEh5DLn&92(AK`V_C{`Lj(mQvsrX*jp ze~AHhhD7b&kuVEuO;%0^RrXrGDq(=#>HxaCt;LQOfe}c0ywd^wk)Cr|S-UKhFu+c1 zFx$APgj8roZSvToYmL*V05ov-<_~~QxgEN#UA-etx;WgKk=(!2M0c%CGKJq=b2%lN zi8%l5eSn?y-x*L^lIS0=)-mLb&VQN(&<23Hvw9~^iT?3w z<@~ofpW|u!`7!V*d&J)di0phyS5lyOJ@%&<=0qmVW^IgDQyDpnze~68Dg85gL*E7>o?cW-e?@Jg&Dk37z3;(m zqepbF=nXT#)6NHoMRv5ax2n6VmCR3J*0>6POff(ex`QcF4M$`|bZ9KFs%O^jtlqER z2l%CCPc{fD0zdoiOjAm-Go$yb6Zk96N6d7`vhurR-v#kc$5!I$0O}5cDr8#H6#?k} z$(Xn9eu|2kz>{4i>u&u^e=+1u=q@^+#ESlZ083e%Y!Y(6GXMYp07*qoM6N<$g6lCG AJOBUy literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_42.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_42.png new file mode 100644 index 0000000000000000000000000000000000000000..15168cd11124217a5092687483149426b63aebba GIT binary patch literal 1495 zcmV;|1t|K7P)xkkIPCPs3`dZ>^RC9n@{P#p%><)z0{AjGhYtt9 z#48*D)9cr(Bgewb$geU!mJ{G_U!!{@Ishg-;t1BUaMor;Ff;NoeTt~Abge{RJAO?E zz(gt?A+pI>=reF;#LskYx@X)T9<)ld;4ug-@T6yy=AAOY?1<-rq2JFqy>~6O$w3KJ zJA$;1d)70@RcC*fVOGRTdUztW8ePtVKB#sCN)NB2nF1dlt42Q7mFnx^k1@j$Xy*BF z0J`uDN665t!mNn*$US0kuF&J;(0*^N!J!#gD%`w+aSCyc<#C2tj?n3zWqeETZ1%8@ z5v(WXC1wCln98i6(W2?}jGADk@in7XWR5J@8h~3Q-K#7ZH6D^PRDjkWS>tPl*Nh(3 zL)&w2`e(ZU46jh5jzA6Rt(+?}0F|ZE_>yi}`MvvWrGG5j*3jxqYKhhematx06;4o* z_ATRkvcPPxhVQzx)|w;?cg9&vI`PrZc)JA8T8mDV@vRI;dCmfteIzH?;Q#jls^D=1 zZcSD36K$m`jW2Dwwr&>OPS7SxBSp5?@X<)m6rBBY6~@>2bH=Yc3M{!ehcLT<3ZcBw zfsr+2#1PeyACb7Iss=7_ZLDcm}!_@9pg=l z7+;ffhVdyc?e_{ya{z$zTAnB(#|PvK4fXQloK%?d}@tChHG^mlLt9tl)^YebKd*;L^V5?5{?r-T!ei;NHIq znAWaU!4bwYdepO^RsJ2-XTMZbYEDoAO6wy7NE0(lkk!&Z#@W%&8Q*dOjz$!mE*~{O z_DU671)dF`Rrzz1K4}a*3t|SyyfBI2F3xgw5mt?8$5xU7o`@N`MeC~({#J3@k;(ub z!mGgA4F9Tef;%O1>nMYLP z7%~2e=OYH!a$S)LuEfrz^+@E8w1QWH(}PRPPsfgp%1r)l z5j&Uu`;|NMxv}rlBIcX2z|N)rewEIAeEnfZ%1ZRBl=eDO_uK= zMRIm5Y&p@Lz-6dA$~hBn|1*e2K<1smN}H#>1j?r6NNZf_Y+1esH6%@cp7}tvGFO4q z$&0Eq9>pl%R}t6+(9ZS_>9|-GQn4D*iFQWTnOqe>qkMPzz}x4qQs7xwty8JS0id7t z8df)cM@5m!%}4O)oLk>9!h4kO(DwnJj0zpE+NTKL)Hi|vo)i5XxH$k9Q5Eejx873> z;?Iom4QBvJ=+ziPj#Yb)ZG#6pN{RyjbUOe5002ovPDHLkV1jaF)=B^X literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_43.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_43.png new file mode 100644 index 0000000000000000000000000000000000000000..16196a7062fb707b4adc7a2199a42d9709024ab5 GIT binary patch literal 1440 zcmV;R1z-A!P)7U9a@zky#-pYv!KVgZvz+5t*YFVhtb-(%y?K7`?KioPyUMwdCiB&ynu6BeyQr z^e>(QD6C3FID#g_S|eD-=D-WlNb3K}j#kAW~YV;#0$yx@WV`u1kUHaGWa`$Rbd>B-N9iks$P5+}( zzei?-Bith@*HwXi3EmgLdlGg}{oH9DOX1@=k9wkiR;KWtP-bQ{i&NIfLOhlNs7Lj= z8u$r8!tT*8;noTu0AIne>!L{MpWmNp8$J6+%LMqU0dh{@ElPHDgk0s1m>K;&>$Hyy zp!Lk760Vk7x8g425<5k=9>3#Z{KkSEFO8CT;*d{ZnX}L3{W>&(o`K5nSJsZ~;KFL_R>iI;QtDr;rNCnUM6A^z_1O zS5$!1%qw;RxlnIkU>D?ct<4DD=2%o9)Xw{H3g830N5h@*1{=Ki^_xLF^`An1WJ}v~ zG>%-i+Ib&ND6fP|1>zgX2dMj9e2S(Hl0M#fzyC_u z+nYTjQM*pLo`f_9=cH!dU!6eh6mSChHTHRvc4uc3G}oYssm^bR;5{;v)4zq2F}Px(Zqf3t-41= zzPISL+G~N7{@H9-N-2_HPb;Psa*{Eeu@qi%y$ha6KGm%iuaRJhf^viHQ@el+Wi2Bl z^hS>5`E2s7a~$2(v~2luf-<27eLvg*Bm;WK_2?cI`4RFn zw}O^!-2KZ_eMeifJIM$5Jy5xWd=A-lfOq{$Dc@ZH6_#PZ-Q-tfSNp4x&)H?cPX@>^ z0ATJBt`~Qc@3E7jhcC`n^ACi0;9ZPaj)IA`lCRl1oBUo~1)Tv@3~>N}d8GEhLVjzD z98Lal9G`zJn<7YefK{Wv0+TFd06g|iTd6aSs2iFugCf`=`YWvIe^%7W?cb%IBr&a|6#NMy(2Cee1xFhff?H-Ctu>KD+Azzq8*)q zzICIYjnq5a=_LG|1bQ>Uu8__4cdg+`(|WyHBmW7l z;G1z`Qn?dAiTo#R2NZ8|YF8If@nrJfhLcPG^~&w}QWx-tJ#k8B``Vt5uYcGZ%`O1o zJHkEh0CwvVR(vlo8Yh69{xPJ?Ae}wqetPvSg4+8g8~{)(kq@9($M~M)6kH*BCpddK zJH7DED=R=EdfAgeD%5)}unSr*fg%|JXA|rAj5Uku{pkYe0B>u!GoCO9FTQ>=h^GFx zknfEi4W8CGbKRnPFG?t_gj)sT6UYbX|4rPiH10*O-U|!iBAvt2P6DMlc;-esqgGbQ z3Z!1WC%s|m^PfOE#pQ)5%r(^5&>7)a!L!u}8D>7_1 z{n4m5I6@Se4s=HrYW~fjH;~`k?cBXaJ^KFxQ_;Jyc>n*600000NkvXXu0mjfVSBd? literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_45.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_45.png new file mode 100644 index 0000000000000000000000000000000000000000..5a2221cb9282fccb2758f6d5f0d0d854d864d06f GIT binary patch literal 1464 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 AOaK4? literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_47.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_47.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d5407ad0f5f04dc351b8d5fb995f2c99094d34 GIT binary patch literal 1369 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 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_49.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_49.png new file mode 100644 index 0000000000000000000000000000000000000000..0e6845ac244980c1d2fcea4abc84ef0b33b215d9 GIT binary patch literal 1851 zcmV-B2gLY^P)Wqssi>-iO&uk9PLGs^@Sv~@?<@>&HLz*6iA zaTp;g3s-YKv;U|vFv79)u=|0136&9|_exhTtin4)#qUy@Q6T zfXKj1f54dItlGaaP%7S48hFVkiBUXOjTlNA8HM)d>& z3xKS=QLM`Np1R$;){2~uawE<$kah1BR1C3n99agAaQ+bip6wyFZHvDHFhR2e!KzVu z{_37!rSq@Q4_G>fJ_OAO1Sv2$dM=uGitu2w;BMmj^URJ01@t7D*#67XA}rk=QCMW zZ&GoFHy-D{In3y1diAFNB4`Gz4EJihCyOnTZIpgC;{4U9FyJg4$^as@e+Bg5Q8bS6 zGR+HuYSUMtbnjGxvhd!T-=p`?9)O{8eCcTtEgfE2V6rl$skf<%0xr{Y^y+m#1sK*(+|+TNqvo8#Ha?5Wm$Pw&&)1g6|FFf-3;WGn+M-5H&1ezw10wq)#> zUBf-bnuQkwcn#33ZvtnWkF#}kr1s;u%6?_aqc^ulr`Eguz3&%<0xeWGaVA*l5y_oO zScAr7SFaV@(XQ+Xh5>DOM8;)}ZAUC-#F@?);b-fn51&O&*7LONmCoPy{lmf0$%U2npl49PsVHhi}8QLbfQMYd-XWq`~g*cA<4?bKc{o4v8tx>h(pJ1?St zE0OVPGC<{ODbC`kKtZa+l4a3s=zFH4x3{wN_mqiY2Cy2TZ$q|MV3f-;9e-Dx&z@I;1@XZEdLb3#MvS-v zbf1t31lA+tWz{Zl*-JayCFoQL}jn^pk0H}1t z;dc!d3H<9%=55s0K1~zV*z?OzqH2tZ^!UE8+(4FIbQSedVd z-JJm<7DFdk*%l!i2woCKO{3NoCG%Sk;B}c%=HHnC+NSH0W{nfcQG7#`7*?~$7(w5A zKGL$h9zxspv@$u5KO&qh$ay}dP#0Og7w+8`()t!6K zEky65+OEe`_B!i)5qbZE5H!T9`QPe%1Y1A5pRs<6X&3{raavB+`6BY(1Y(VkXzE)U zL4>tw>_m{s#>#t3UUc$c?;_{FP66$QS7-j?^Hij-z3`5oUiTi^iDRus@qrV*oz|;} zGT(DxyN(1&blS+u(9nKPeF^-gqhAla%#X^XNZk3a1oM^lZ`WT0vEX1hYtg-E_D0`B z*cD-&=d1S2fOo{7^8W%D#o&4R%0PSZdAqkxMUiYh-+PakwRcu8G0Xt0*!m_Q8@F^-4GnaX14o pfU4j-JHMgo#B2{xWq>n!fIogQ{T#2oX!rmC002ovPDHLkV1iOkj#vNy literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_5.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_5.png new file mode 100644 index 0000000000000000000000000000000000000000..45decf285fb34e41768e7304fa41765308dbe80e GIT binary patch literal 1625 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 KMNUMnLSTZ-kN8Re literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_51.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_51.png new file mode 100644 index 0000000000000000000000000000000000000000..38184aa75e307e689cff898bae3a09765ef43093 GIT binary patch literal 2258 zcmV;@2rc)CP)yrx@}qw{e!5KH$c($X zwqqT@0LpNxBw>WAE&R3QGylKU26h=>r3HL206TykMnE=*4%|^GC*;n`kNQz|V|Dia z=>OL>o?Ycx6-LFl7N2zvxw3m&zDf5EvvpXwtNV$GaSgdZz;(=?1BP$PH!2=!I^M_k zj&$?*w*3MNT?Lhc&V0a_eLDl7yw*-yK+~>uk`KJSUY+?+RaEl2D0hBBOOPSjc>MrZzTU40C#7I>$>Xi z0hprGKu|p@?!S8`xHI{GVIEL6x4sBE0R#mAW#cpmu>Gti-%0#8hgl}H{SE?vuA{3! zP|2~;Zg>SOqy1Hc$O zxjO)ed!kf8=q8`(QnN`X8QFT=`y*juo>{e9{z}+MxuaiR*Y%NL1}r?lmE_+oD+RDC zUuA$X@{df4T04hQRf9Vl;J&%H8j@W~&pwr)F8o>TU$Ohu86X;7*|)m4+ZL3LyN0?7 zaL&xJYB&8V_=G4&8LHKu>VC(5yyqS;`m3b-Sv=F*nL~E$KC?q$#+8HBzPUc5vkVlt zK3liDhv{$*_jC_;3Sn2C&H%IYbgrEkV>}pd_Q{3C#MXZ>03w(nI+LvOPxdZHxSvqMzR z?iK_>^a9de10nV4yc%@mZWSb-5;LodZT7&ofX5T>0iEpH;f+=iILV`(RYpWdKG|Y|U>8JCJ$ZZ4byK6$m<& zAN49W$QYTiA7y|p2$XU)6J+o25;Z$8;AT29e;E+s&n!8svz4;H(kA2#&~XwK#%l~Z zOF-t}j;Q3L?#fQ2U>68;J*#wl-${OCg!pp7g7Rj76(`X#d`$z{HIp4Cag*-~##8}; zwHG((7&qnv{h4-DQDyC6?xnvG)JeWVB|6uoD|Hy^{j|68%=M=Ng1Wa#`>Ox5_e@a# zj3df}Dd;4hF#v)9opHpSDeyiX3|8W4O1Obyp}vr__3dSQN$_Oiw5Iof$+4t8_N^ zWHW+O*(i=qJX`h*&*OoK&Wtf7Sz@LUHn5<>_+m4Jy1L1aS65iVS={QL(pmY@DZuDk z<^wB+2Qz|6aulNCDlsw9?4>|d%>-^d4iMsgOn$~DyG+wfKKje%G3DRK_W)TRTj~9{ zKHjgurI?h)V z27;<8vv#F`&f17W`>O++Vj~5{6&om+t7-Qc-!S9M5p}3hs^q#3GX{u0s9w#k(RP){ zPD{&ZUB!{Lq!S6pSeWhWy1c&|7&lIZE@+|?uC40ulwX;ixsLf#&o2RXNps5Sc=?lISz8bA42^NEP?WpqJ^3eou+MKinjuutTfb zLMN%+%5{^^{8Q{S6N2r9#ZnECDsDE5tO7yp%i{g`eSnT(1%hm_spz(96>49W@XY_X zo=J?O0us}Y`?Gl1ImTCJhs`3&=8qX*HTg_gb;aPEzRK1`LFRJW2h-63rPDSMT#i4g zl_NE#VAf&RHAJDm;qJ?j?Uq*Ltw)XzEDT(b1}#) zxy)atyVI7YzIg4Nk6IV)M*F*hcB4N_|4yJwYiNue!b~6oBJOeRu=mk#1j5b?po(XO g0lK~1l`O9R0h`z=xZ>{7K>z>%07*qoM6N<$f}HGIiU0rr literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_52.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_52.png new file mode 100644 index 0000000000000000000000000000000000000000..1259a591a4b81d5bf1d12cf1d6dc739f94e88a16 GIT binary patch literal 1615 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 literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_8.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_8.png new file mode 100644 index 0000000000000000000000000000000000000000..3621243f71f10b63c819eca3ae8474717db41550 GIT binary patch literal 1612 zcmV-S2DABzP)c?O7i*cfGg~qE&{Vk${ma@O3rf!@U?EU@0qaf5RNJ-cQCr6@96x2Ob~R~ zH&p~`6Gl#w3(CxKH|G=4lf!q|H{AtPgCHyWj?N#b1OX~{j34hyZD1w{_-EcCzRrIJ z8U(ZUHH*MZaiQfbOKD9`)+?f1Ri{~bGl5dw`4Oz{0JX0fjF~ntQc#;TtDHw+-k1m- z0glYU$9C5;Xb|wZ!vd063WywG!Rtpg=Uq|ob<_VaDj(V^ZZtB8}+?l|UXB65PK8NRg zEf8mz@d~DR5WU}*FK5$>SA59>8!2C&pn1+Z~%1XAjEK4IUMLorS=3b>JF^=yx%*qqzJSo z(jF_$FhNJ#wBmSm=Gn(g4N}3jB2eyl>GZ1eqqZwTHccRUAsvG?-@CQYS^Ne7y5l1z zu=1$3<11KoScM!8S@ZE?bjRspCl31mm9VT+GjxsSJ^e&?^+B6mAq(+9mr`x$2j<43!PNN2g3R&@tl2B*uLDo*!`h72|Iqnb)NTolhKiV{2VToLy0mJ~BB33_s7w22FuhmKN zJtB+W6S2$GT8PyE5-1&+!V`xgp91a>X%{UBv;dHsO1oxtTb@sldX3{ePoDwgf>C6O z9y$I~f`RKSZNzPuEy|>f=(@%R85{n7Eu6o0IbTa3T92GbGk+D)TC;To3Y7tdzz*kI za%91&MQ=6r?0`k-{5nw_&{1lzWLT`@&85|JFXsT-Kz@U^NN=H)J~isAuSQe^TF9Ok zSoff^kvU(!6pB>-Xlvs+4e36#Jo*lSpg9`Jzj6&)*I?bF%_aS&=@GF)_{X8hZuBZx z3);Cu6a?B_SD`Y$)h&2MINC8-4v&2D5&%f<=mKg8%^=x8SiOb{vTN7w9q;+)TsQ4= zj;8>Kb}mZ&C^8HXMK(gcD`4e)G$>?XTd&@|)$2s83#dY?9}sz&=&vxsN~ddUk;oK- z7OYxm#%FSF^;rNyL6%Tdv1q4fgCTPK?wY}x4`tb?AnsZZ{Cxng^+6UUf$Z!|5OBFy z7l;-t$7R#tc<N6V% z6}qn&57lF=Ba3X>=?L;6-*U9I_H+%v6_yLI7K0i{8`H%A2&%eDc=KuUx|mLrFa4zH z$L~oq0P1`%7_@vgYlJ9hH3M|l3aisv2gAvAA4L9t8YOd0lzYaQXeU)t1`02D$94JH zCqWDLD%$?F@F$_5LJOvL^;kXME}%>Y$)bP(J{1xDe>$@Dj)i~MKbMr*&bD^|0000< KMNUMnLSTYT=Jyc* literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/frame_9.png b/assets/dolphin/external/L2_Secret_door_128x64/frame_9.png new file mode 100644 index 0000000000000000000000000000000000000000..4d3d537162cb4c59a4c379e0493749eabde8edad GIT binary patch literal 1575 zcmV+?2H5$DP)pcN0+xJWYqe}7!LpR0Oc>?HOSF`VnM@v`EnoQ@=dDY7O7f^?jPksv_j_VH2szLkNIAfTV2boONDcc4LVm3_@l zpp>|1N=wl?LSdqk$@x)O>!DeE)IJsVMQp(3xUFDINpxNoRnE=oGU|Lwj~VujR1km4 zKxv{Esa$D~mZEoC6qf~#4s_YxVb~q9uLBPjJn{*XQMzn^sp(b8KTAyIH z^IHqP4YU@QHn9>$>0dkf)%)}8H_N_fD|n>j&^}+y`4Z3*J>$Cal1yn#Ca0ph@%ejH zD0MJ5&=t;~-AC_`Xcqxu1GE8@wJ(xThQ1Lr+xS;GSAtiIBk1~%=0A}&s>bgbWvVe! z$5w$iXAoG_D#@-uHN%PlaOX+%P+b~w*|SR2OcgW}`^wI)Ld5yVsg9PVD<{R}SHLF* z6g~M-XCnKpv`MvnFUbMWyD}@Aqq<#P(U4jVmjr;+`{tiVz-35|JdOi$@Td+moFBW4B(WP>dvWC`PV~3XD2On#b>Ii4j)B$p9Kv)8|)2b2LAY=A(LMov)pCl=3sz zRuxVLKz~|@BvKKK-qABb_bS;YQc~a9INGyL?~oMF*4Zn9GiEe@L9g7aATofYD4L~P z6#nUf;8iaO18N5=(t3`J_h2$WUnp7=b2*tN(<(p`KkIp=9+h}WCqJqTbued;JNo5U z!8?sJlDx`bI*#M_e+Q4`09wRHa*9u41kV<&`R`1uF{lnz=>FLG$@dnKPCftK$|sHQ808u7D4&&RGLbdEYvMG;AJjVHiK(I<(Z=5wAg~gO8 z1D`p7rWkT9Sjt(n&&NsgJ|Pe&v}-{^_Nue0j)?P*flk5b%7c;!wRtP9CbLmG~j+Awkm7jZX8046{*3(tpx^ zBz@^;QjkP-;m)V)XMU=E0E-E%%|4Mtc&nxAC^&-os`dU|?#OY`Wu z(&v`VQ9o&VQNRqKZJHa5Z$LUh-p^`A&_GYT=6pm?Pw)PmucPThZOvI>WWN$4p3ho~ z{jFfnsH3NT7PQkwpJ~sp&><=#D~H4VYvFH$!G!}NAA@WjH7yTo0S5RY4t^D6kjbkw Z`~cbttH@|hC}98q002ovPDHLkV1k|1=!pOT literal 0 HcmV?d00001 diff --git a/assets/dolphin/external/L2_Secret_door_128x64/meta.txt b/assets/dolphin/external/L2_Secret_door_128x64/meta.txt new file mode 100644 index 00000000000..4091b12769a --- /dev/null +++ b/assets/dolphin/external/L2_Secret_door_128x64/meta.txt @@ -0,0 +1,14 @@ +Filetype: Flipper Animation +Version: 1 + +Width: 128 +Height: 64 +Passive frames: 29 +Active frames: 24 +Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 +Active cycles: 1 +Frame rate: 2 +Duration: 3600 +Active cooldown: 7 + +Bubble slots: 0 diff --git a/assets/dolphin/external/manifest.txt b/assets/dolphin/external/manifest.txt index 1d3f3510689..d7348b25cdd 100644 --- a/assets/dolphin/external/manifest.txt +++ b/assets/dolphin/external/manifest.txt @@ -175,3 +175,10 @@ Max butthurt: 12 Min level: 2 Max level: 3 Weight: 4 + +Name: L2_Secret_door_128x64 +Min butthurt: 0 +Max butthurt: 12 +Min level: 2 +Max level: 3 +Weight: 4 From 890c9e87ceac86dc3d70dd3f09657483b1c4209b Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 1 Dec 2023 13:16:48 +0400 Subject: [PATCH 05/14] [FL-3690] Libraries cleanup; u2f crypto rework to use mbedtls (#3234) * examples: plugins: utilize fal_embedded * libs: removed fnv1a_hash * furi: added FURI_PACKED; apps, libs: changed to use FURI_PACKED * lib: mbedtls: using custom config * lib: toolbox: removed md5, switched to mbedtls * targets: f18: link fix * lib: added mbedtls_cfg.h * apps: nfc: explicit dependency on libmbedtls * u2f: reworking to mbedtls * u2f: replaced sha256 & hmac with mbedtls * u2f: functional rework using mbedtls * libs: dropped micro-ecc * u2f: dropped old implementation * toolbox: removed sha256 impl * mcheck() for mbedtls * libs: removed libmisc; split into smaller libs * apps: debug: fixed display_test * apps: include cleanups * fbt: fixed VERSIONCOMSTR * furi: added FURI_CHECK_RETURN * lib: removed qrcode * cleanup * fbt: lint_py+format_py: fixed excessive command length * api: Removed bzero from f7 * api: Removed bzero from f18 * Bump API Symbols Co-authored-by: Aleksandr Kutuzov --- .pvsoptions | 2 +- SConstruct | 11 +- .../debug/ccid_test/iso7816_t0_apdu.h | 4 +- .../debug/display_test/application.fam | 2 +- applications/debug/unit_tests/rpc/rpc_test.c | 36 +- .../example_plugins_advanced/application.fam | 2 + .../example_advanced_plugins.c | 5 +- applications/main/nfc/application.fam | 2 +- applications/main/u2f/application.fam | 2 +- applications/main/u2f/hmac_sha256.c | 98 - applications/main/u2f/hmac_sha256.h | 38 - applications/main/u2f/u2f.c | 243 +- applications/main/u2f/u2f_data.c | 2 +- applications/services/rpc/rpc_gui.c | 5 +- applications/services/rpc/rpc_i.h | 2 +- applications/services/rpc/rpc_storage.c | 16 +- .../storage_move_to_sd/storage_move_to_sd.c | 4 +- furi/core/common_defines.h | 8 + lib/ReadMe.md | 5 +- lib/SConscript | 73 +- lib/appframe.scons | 3 + lib/digital_signal/SConscript | 3 + lib/drivers/SConscript | 3 + lib/flipper_application/elf/elf_file.c | 7 +- lib/flipper_format/SConscript | 3 + lib/fnv1a-hash/fnv1a-hash.c | 10 - lib/fnv1a-hash/fnv1a-hash.h | 39 - lib/heatshrink.scons | 23 + lib/infrared/SConscript | 3 + lib/mbedtls | 2 +- lib/mbedtls.scons | 32 +- lib/mbedtls_cfg.h | 92 + lib/micro-ecc/LICENSE.txt | 21 - lib/micro-ecc/README.md | 41 - lib/micro-ecc/asm_arm.inc | 821 ------ lib/micro-ecc/asm_arm_mult_square.inc | 2311 ----------------- lib/micro-ecc/asm_arm_mult_square_umaal.inc | 1202 --------- lib/micro-ecc/curve-specific.inc | 1249 --------- lib/micro-ecc/platform-specific.inc | 94 - lib/micro-ecc/types.h | 108 - lib/micro-ecc/uECC.c | 1669 ------------ lib/micro-ecc/uECC.h | 367 --- lib/micro-ecc/uECC_vli.h | 172 -- lib/microtar.scons | 2 +- lib/misc.scons | 58 - lib/mlib.scons | 27 + lib/music_worker/SConscript | 3 + lib/nanopb.scons | 31 + lib/nfc/SConscript | 3 + lib/nfc/protocols/mf_desfire/mf_desfire_i.c | 14 +- .../protocols/mf_ultralight/mf_ultralight.h | 2 +- lib/print/SConscript | 3 + lib/pulse_reader/SConscript | 3 + lib/qrcode/qrcode.c | 975 ------- lib/qrcode/qrcode.h | 99 - lib/signal_reader/SConscript | 5 +- lib/subghz/SConscript | 3 + lib/toolbox/SConscript | 5 +- lib/toolbox/md5.c | 299 --- lib/toolbox/md5.h | 83 - lib/toolbox/md5_calc.c | 44 +- lib/toolbox/sha256.c | 221 -- lib/toolbox/sha256.h | 24 - lib/u8g2/SConscript | 20 + lib/update_util/SConscript | 16 + scripts/fbt_tools/fbt_apps.py | 1 - scripts/fbt_tools/fbt_version.py | 4 +- targets/f18/api_symbols.csv | 211 +- targets/f18/target.json | 12 +- targets/f7/api_symbols.csv | 213 +- targets/f7/furi_hal/furi_hal_usb_ccid.c | 6 +- targets/f7/furi_hal/furi_hal_usb_cdc.c | 4 +- targets/f7/furi_hal/furi_hal_usb_hid.c | 12 +- targets/f7/furi_hal/furi_hal_usb_u2f.c | 2 +- targets/f7/target.json | 8 +- 75 files changed, 888 insertions(+), 10360 deletions(-) delete mode 100644 applications/main/u2f/hmac_sha256.c delete mode 100644 applications/main/u2f/hmac_sha256.h delete mode 100644 lib/fnv1a-hash/fnv1a-hash.c delete mode 100644 lib/fnv1a-hash/fnv1a-hash.h create mode 100644 lib/heatshrink.scons create mode 100644 lib/mbedtls_cfg.h delete mode 100644 lib/micro-ecc/LICENSE.txt delete mode 100644 lib/micro-ecc/README.md delete mode 100644 lib/micro-ecc/asm_arm.inc delete mode 100644 lib/micro-ecc/asm_arm_mult_square.inc delete mode 100644 lib/micro-ecc/asm_arm_mult_square_umaal.inc delete mode 100644 lib/micro-ecc/curve-specific.inc delete mode 100644 lib/micro-ecc/platform-specific.inc delete mode 100644 lib/micro-ecc/types.h delete mode 100644 lib/micro-ecc/uECC.c delete mode 100644 lib/micro-ecc/uECC.h delete mode 100644 lib/micro-ecc/uECC_vli.h delete mode 100644 lib/misc.scons create mode 100644 lib/mlib.scons create mode 100644 lib/nanopb.scons delete mode 100644 lib/qrcode/qrcode.c delete mode 100644 lib/qrcode/qrcode.h delete mode 100644 lib/toolbox/md5.c delete mode 100644 lib/toolbox/md5.h delete mode 100644 lib/toolbox/sha256.c delete mode 100644 lib/toolbox/sha256.h create mode 100644 lib/u8g2/SConscript create mode 100644 lib/update_util/SConscript diff --git a/.pvsoptions b/.pvsoptions index 0312180924d..3337d7eb5c2 100644 --- a/.pvsoptions +++ b/.pvsoptions @@ -1 +1 @@ ---ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/micro-ecc -e lib/microtar -e lib/mlib -e lib/qrcode -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e */arm-none-eabi/* +--ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/microtar -e lib/mlib -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e */arm-none-eabi/* diff --git a/SConstruct b/SConstruct index a2c5cd9e7af..b42218a579c 100644 --- a/SConstruct +++ b/SConstruct @@ -288,13 +288,17 @@ distenv.PhonyTarget( LINT_SOURCES=[n.srcnode() for n in firmware_env["LINT_SOURCES"]], ) -# PY_LINT_SOURCES contains recursively-built modules' SConscript files + application manifests +# PY_LINT_SOURCES contains recursively-built modules' SConscript files # Here we add additional Python files residing in repo root firmware_env.Append( PY_LINT_SOURCES=[ # Py code folders "site_scons", "scripts", + "applications", + "applications_user", + "assets", + "targets", # Extra files "SConstruct", "firmware.scons", @@ -304,7 +308,10 @@ firmware_env.Append( black_commandline = "@${PYTHON3} -m black ${PY_BLACK_ARGS} ${PY_LINT_SOURCES}" -black_base_args = ["--include", '"\\.scons|\\.py|SConscript|SConstruct"'] +black_base_args = [ + "--include", + '"(\\.scons|\\.py|SConscript|SConstruct|\\.fam)$"', +] distenv.PhonyTarget( "lint_py", diff --git a/applications/debug/ccid_test/iso7816_t0_apdu.h b/applications/debug/ccid_test/iso7816_t0_apdu.h index b66d66054da..5ca13eb6041 100644 --- a/applications/debug/ccid_test/iso7816_t0_apdu.h +++ b/applications/debug/ccid_test/iso7816_t0_apdu.h @@ -13,12 +13,12 @@ struct ISO7816_Command_APDU { //body uint8_t Lc; uint8_t Le; -} __attribute__((packed)); +} FURI_PACKED; struct ISO7816_Response_APDU { uint8_t SW1; uint8_t SW2; -} __attribute__((packed)); +} FURI_PACKED; void iso7816_answer_to_reset(uint8_t* atrBuffer, uint32_t* atrlen); void iso7816_read_command_apdu( diff --git a/applications/debug/display_test/application.fam b/applications/debug/display_test/application.fam index 6a2d9c20c1a..7b2357b01d8 100644 --- a/applications/debug/display_test/application.fam +++ b/applications/debug/display_test/application.fam @@ -4,7 +4,7 @@ App( apptype=FlipperAppType.DEBUG, entry_point="display_test_app", requires=["gui"], - fap_libs=["misc"], + fap_libs=["u8g2"], stack_size=1 * 1024, order=120, fap_category="Debug", diff --git a/applications/debug/unit_tests/rpc/rpc_test.c b/applications/debug/unit_tests/rpc/rpc_test.c index 5659ba877df..3faf6157211 100644 --- a/applications/debug/unit_tests/rpc/rpc_test.c +++ b/applications/debug/unit_tests/rpc/rpc_test.c @@ -1,27 +1,31 @@ -#include "flipper.pb.h" #include #include -#include "pb_decode.h" -#include -#include "rpc/rpc_i.h" -#include "storage.pb.h" -#include "storage/filesystem_api_defines.h" -#include "storage/storage.h" #include -#include "../minunit.h" #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include "../minunit.h" + +#include +#include +#include +#include +#include +#include + LIST_DEF(MsgList, PB_Main, M_POD_OPLIST) #define M_OPL_MsgList_t() LIST_OPLIST(MsgList) diff --git a/applications/examples/example_plugins_advanced/application.fam b/applications/examples/example_plugins_advanced/application.fam index 0c7e3e3b94d..10fdc042ff2 100644 --- a/applications/examples/example_plugins_advanced/application.fam +++ b/applications/examples/example_plugins_advanced/application.fam @@ -14,6 +14,7 @@ App( entry_point="advanced_plugin1_ep", requires=["example_advanced_plugins"], sources=["plugin1.c"], + fal_embedded=True, ) App( @@ -22,4 +23,5 @@ App( entry_point="advanced_plugin2_ep", requires=["example_advanced_plugins"], sources=["plugin2.c"], + fal_embedded=True, ) diff --git a/applications/examples/example_plugins_advanced/example_advanced_plugins.c b/applications/examples/example_plugins_advanced/example_advanced_plugins.c index 2b137e1d484..77ab8205103 100644 --- a/applications/examples/example_plugins_advanced/example_advanced_plugins.c +++ b/applications/examples/example_plugins_advanced/example_advanced_plugins.c @@ -23,7 +23,10 @@ int32_t example_advanced_plugins_app(void* p) { PLUGIN_APP_ID, PLUGIN_API_VERSION, composite_api_resolver_get(resolver)); do { - if(plugin_manager_load_all(manager, APP_DATA_PATH("plugins")) != PluginManagerErrorNone) { + // For built-in .fals (fal_embedded==True), use APP_ASSETS_PATH + // Otherwise, use APP_DATA_PATH + if(plugin_manager_load_all(manager, APP_ASSETS_PATH("plugins")) != + PluginManagerErrorNone) { FURI_LOG_E(TAG, "Failed to load all libs"); break; } diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index 33a2011a70e..9a98b57c8c3 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -13,7 +13,7 @@ App( "!plugins", "!nfc_cli.c", ], - fap_libs=["assets"], + fap_libs=["assets", "mbedtls"], fap_icon="icon.png", fap_category="NFC", ) diff --git a/applications/main/u2f/application.fam b/applications/main/u2f/application.fam index bf41eb0f7a5..5e0cde736c9 100644 --- a/applications/main/u2f/application.fam +++ b/applications/main/u2f/application.fam @@ -7,7 +7,7 @@ App( icon="A_U2F_14", order=80, resources="resources", - fap_libs=["assets"], + fap_libs=["assets", "mbedtls"], fap_category="USB", fap_icon="icon.png", ) diff --git a/applications/main/u2f/hmac_sha256.c b/applications/main/u2f/hmac_sha256.c deleted file mode 100644 index 611aa2a6f48..00000000000 --- a/applications/main/u2f/hmac_sha256.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * hmac.c - HMAC - * - * Copyright (C) 2017 Sergei Glushchenko - * Author: Sergei Glushchenko - * - * This file is a part of U2F firmware for STM32 - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * As additional permission under GNU GPL version 3 section 7, you may - * distribute non-source form of the Program without the copy of the - * GNU GPL normally required by section 4, provided you inform the - * recipients of GNU GPL by a written offer. - * - */ -#include - -#include "sha256.h" -#include "hmac_sha256.h" - -static void _hmac_sha256_init(const hmac_context* ctx) { - hmac_sha256_context* context = (hmac_sha256_context*)ctx; - sha256_start(&context->sha_ctx); -} - -static void - _hmac_sha256_update(const hmac_context* ctx, const uint8_t* message, unsigned message_size) { - hmac_sha256_context* context = (hmac_sha256_context*)ctx; - sha256_update(&context->sha_ctx, message, message_size); -} - -static void _hmac_sha256_finish(const hmac_context* ctx, uint8_t* hash_result) { - hmac_sha256_context* context = (hmac_sha256_context*)ctx; - sha256_finish(&context->sha_ctx, hash_result); -} - -/* Compute an HMAC using K as a key (as in RFC 6979). Note that K is always - the same size as the hash result size. */ -static void hmac_init(const hmac_context* ctx, const uint8_t* K) { - uint8_t* pad = ctx->tmp + 2 * ctx->result_size; - unsigned i; - for(i = 0; i < ctx->result_size; ++i) pad[i] = K[i] ^ 0x36; - for(; i < ctx->block_size; ++i) pad[i] = 0x36; - - ctx->init_hash(ctx); - ctx->update_hash(ctx, pad, ctx->block_size); -} - -static void hmac_update(const hmac_context* ctx, const uint8_t* message, unsigned message_size) { - ctx->update_hash(ctx, message, message_size); -} - -static void hmac_finish(const hmac_context* ctx, const uint8_t* K, uint8_t* result) { - uint8_t* pad = ctx->tmp + 2 * ctx->result_size; - unsigned i; - for(i = 0; i < ctx->result_size; ++i) pad[i] = K[i] ^ 0x5c; - for(; i < ctx->block_size; ++i) pad[i] = 0x5c; - - ctx->finish_hash(ctx, result); - - ctx->init_hash(ctx); - ctx->update_hash(ctx, pad, ctx->block_size); - ctx->update_hash(ctx, result, ctx->result_size); - ctx->finish_hash(ctx, result); -} - -void hmac_sha256_init(hmac_sha256_context* ctx, const uint8_t* K) { - ctx->hmac_ctx.init_hash = _hmac_sha256_init; - ctx->hmac_ctx.update_hash = _hmac_sha256_update; - ctx->hmac_ctx.finish_hash = _hmac_sha256_finish; - ctx->hmac_ctx.block_size = 64; - ctx->hmac_ctx.result_size = 32; - ctx->hmac_ctx.tmp = ctx->tmp; - hmac_init(&ctx->hmac_ctx, K); -} - -void hmac_sha256_update( - const hmac_sha256_context* ctx, - const uint8_t* message, - unsigned message_size) { - hmac_update(&ctx->hmac_ctx, message, message_size); -} - -void hmac_sha256_finish(const hmac_sha256_context* ctx, const uint8_t* K, uint8_t* hash_result) { - hmac_finish(&ctx->hmac_ctx, K, hash_result); -} diff --git a/applications/main/u2f/hmac_sha256.h b/applications/main/u2f/hmac_sha256.h deleted file mode 100644 index add123142d4..00000000000 --- a/applications/main/u2f/hmac_sha256.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include "sha256.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct hmac_context { - void (*init_hash)(const struct hmac_context* context); - void (*update_hash)( - const struct hmac_context* context, - const uint8_t* message, - unsigned message_size); - void (*finish_hash)(const struct hmac_context* context, uint8_t* hash_result); - unsigned block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */ - unsigned result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */ - uint8_t* tmp; /* Must point to a buffer of at least (2 * result_size + block_size) bytes. */ -} hmac_context; - -typedef struct hmac_sha256_context { - hmac_context hmac_ctx; - sha256_context sha_ctx; - uint8_t tmp[32 * 2 + 64]; -} hmac_sha256_context; - -void hmac_sha256_init(hmac_sha256_context* ctx, const uint8_t* K); - -void hmac_sha256_update( - const hmac_sha256_context* ctx, - const uint8_t* message, - unsigned message_size); - -void hmac_sha256_finish(const hmac_sha256_context* ctx, const uint8_t* K, uint8_t* hash_result); - -#ifdef __cplusplus -} -#endif diff --git a/applications/main/u2f/u2f.c b/applications/main/u2f/u2f.c index ce70212a9fa..3bdafe9185e 100644 --- a/applications/main/u2f/u2f.c +++ b/applications/main/u2f/u2f.c @@ -1,18 +1,22 @@ -#include #include "u2f.h" #include "u2f_hid.h" #include "u2f_data.h" + +#include #include #include #include // for lfs_tobe32 -#include "toolbox/sha256.h" -#include "hmac_sha256.h" -#include "micro-ecc/uECC.h" +#include +#include +#include +#include #define TAG "U2f" #define WORKER_TAG TAG "Worker" +#define MCHECK(expr) furi_check((expr) == 0) + #define U2F_CMD_REGISTER 0x01 #define U2F_CMD_AUTHENTICATE 0x02 #define U2F_CMD_VERSION 0x03 @@ -25,16 +29,26 @@ typedef enum { 0x08, // "dont-enforce-user-presence-and-sign" - send auth response even if user is missing } U2fAuthMode; +#define U2F_HASH_SIZE 32 +#define U2F_NONCE_SIZE 32 +#define U2F_CHALLENGE_SIZE 32 +#define U2F_APP_ID_SIZE 32 + +#define U2F_EC_KEY_SIZE 32 +#define U2F_EC_BIGNUM_SIZE 32 +#define U2F_EC_POINT_SIZE 65 + typedef struct { uint8_t format; uint8_t xy[64]; -} __attribute__((packed)) U2fPubKey; +} FURI_PACKED U2fPubKey; +_Static_assert(sizeof(U2fPubKey) == U2F_EC_POINT_SIZE, "U2fPubKey size mismatch"); typedef struct { uint8_t len; - uint8_t hash[32]; - uint8_t nonce[32]; -} __attribute__((packed)) U2fKeyHandle; + uint8_t hash[U2F_HASH_SIZE]; + uint8_t nonce[U2F_NONCE_SIZE]; +} FURI_PACKED U2fKeyHandle; typedef struct { uint8_t cla; @@ -42,16 +56,16 @@ typedef struct { uint8_t p1; uint8_t p2; uint8_t len[3]; - uint8_t challenge[32]; - uint8_t app_id[32]; -} __attribute__((packed)) U2fRegisterReq; + uint8_t challenge[U2F_CHALLENGE_SIZE]; + uint8_t app_id[U2F_APP_ID_SIZE]; +} FURI_PACKED U2fRegisterReq; typedef struct { uint8_t reserved; U2fPubKey pub_key; U2fKeyHandle key_handle; uint8_t cert[]; -} __attribute__((packed)) U2fRegisterResp; +} FURI_PACKED U2fRegisterResp; typedef struct { uint8_t cla; @@ -59,16 +73,16 @@ typedef struct { uint8_t p1; uint8_t p2; uint8_t len[3]; - uint8_t challenge[32]; - uint8_t app_id[32]; + uint8_t challenge[U2F_CHALLENGE_SIZE]; + uint8_t app_id[U2F_APP_ID_SIZE]; U2fKeyHandle key_handle; -} __attribute__((packed)) U2fAuthReq; +} FURI_PACKED U2fAuthReq; typedef struct { uint8_t user_present; uint32_t counter; uint8_t signature[]; -} __attribute__((packed)) U2fAuthResp; +} FURI_PACKED U2fAuthResp; static const uint8_t ver_str[] = {"U2F_V2"}; @@ -78,19 +92,20 @@ static const uint8_t state_user_missing[] = {0x69, 0x85}; static const uint8_t state_wrong_data[] = {0x6A, 0x80}; struct U2fData { - uint8_t device_key[32]; - uint8_t cert_key[32]; + uint8_t device_key[U2F_EC_KEY_SIZE]; + uint8_t cert_key[U2F_EC_KEY_SIZE]; uint32_t counter; - const struct uECC_Curve_t* p_curve; bool ready; bool user_present; U2fEvtCallback callback; void* context; + mbedtls_ecp_group group; }; -static int u2f_uecc_random(uint8_t* dest, unsigned size) { +static int u2f_uecc_random_cb(void* context, uint8_t* dest, unsigned size) { + UNUSED(context); furi_hal_random_fill_buf(dest, size); - return 1; + return 0; } U2fData* u2f_alloc() { @@ -99,6 +114,7 @@ U2fData* u2f_alloc() { void u2f_free(U2fData* U2F) { furi_assert(U2F); + mbedtls_ecp_group_free(&U2F->group); free(U2F); } @@ -129,8 +145,8 @@ bool u2f_init(U2fData* U2F) { } } - U2F->p_curve = uECC_secp256r1(); - uECC_set_rng(u2f_uecc_random); + mbedtls_ecp_group_init(&U2F->group); + mbedtls_ecp_group_load(&U2F->group, MBEDTLS_ECP_DP_SECP256R1); U2F->ready = true; return true; @@ -171,21 +187,63 @@ static uint8_t u2f_der_encode_signature(uint8_t* der, uint8_t* sig) { der[0] = 0x30; uint8_t len = 2; - len += u2f_der_encode_int(der + len, sig, 32); - len += u2f_der_encode_int(der + len, sig + 32, 32); + len += u2f_der_encode_int(der + len, sig, U2F_HASH_SIZE); + len += u2f_der_encode_int(der + len, sig + U2F_HASH_SIZE, U2F_HASH_SIZE); der[1] = len - 2; return len; } +static void + u2f_ecc_sign(mbedtls_ecp_group* grp, const uint8_t* key, uint8_t* hash, uint8_t* signature) { + mbedtls_mpi r, s, d; + + mbedtls_mpi_init(&r); + mbedtls_mpi_init(&s); + mbedtls_mpi_init(&d); + + MCHECK(mbedtls_mpi_read_binary(&d, key, U2F_EC_KEY_SIZE)); + MCHECK(mbedtls_ecdsa_sign(grp, &r, &s, &d, hash, U2F_HASH_SIZE, u2f_uecc_random_cb, NULL)); + MCHECK(mbedtls_mpi_write_binary(&r, signature, U2F_EC_BIGNUM_SIZE)); + MCHECK(mbedtls_mpi_write_binary(&s, signature + U2F_EC_BIGNUM_SIZE, U2F_EC_BIGNUM_SIZE)); + + mbedtls_mpi_free(&r); + mbedtls_mpi_free(&s); + mbedtls_mpi_free(&d); +} + +static void u2f_ecc_compute_public_key( + mbedtls_ecp_group* grp, + const uint8_t* private_key, + U2fPubKey* public_key) { + mbedtls_ecp_point Q; + mbedtls_mpi d; + size_t olen; + + mbedtls_ecp_point_init(&Q); + mbedtls_mpi_init(&d); + + MCHECK(mbedtls_mpi_read_binary(&d, private_key, U2F_EC_KEY_SIZE)); + MCHECK(mbedtls_ecp_mul(grp, &Q, &d, &grp->G, u2f_uecc_random_cb, NULL)); + MCHECK(mbedtls_ecp_check_privkey(grp, &d)); + + MCHECK(mbedtls_ecp_point_write_binary( + grp, &Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, (unsigned char*)public_key, sizeof(U2fPubKey))); + + mbedtls_ecp_point_free(&Q); + mbedtls_mpi_free(&d); +} + +/////////////////////////////////////////// + static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) { U2fRegisterReq* req = (U2fRegisterReq*)buf; U2fRegisterResp* resp = (U2fRegisterResp*)buf; U2fKeyHandle handle; - uint8_t private[32]; + uint8_t private[U2F_EC_KEY_SIZE]; U2fPubKey pub_key; - uint8_t hash[32]; - uint8_t signature[64]; + uint8_t hash[U2F_HASH_SIZE]; + uint8_t signature[U2F_EC_BIGNUM_SIZE * 2]; if(u2f_data_check(false) == false) { U2F->ready = false; @@ -201,40 +259,54 @@ static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) { } U2F->user_present = false; - hmac_sha256_context hmac_ctx; - sha256_context sha_ctx; + handle.len = U2F_HASH_SIZE * 2; - handle.len = 32 * 2; // Generate random nonce furi_hal_random_fill_buf(handle.nonce, 32); - // Generate private key - hmac_sha256_init(&hmac_ctx, U2F->device_key); - hmac_sha256_update(&hmac_ctx, req->app_id, 32); - hmac_sha256_update(&hmac_ctx, handle.nonce, 32); - hmac_sha256_finish(&hmac_ctx, U2F->device_key, private); + { + mbedtls_md_context_t hmac_ctx; + mbedtls_md_init(&hmac_ctx); + MCHECK(mbedtls_md_setup(&hmac_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1)); + MCHECK(mbedtls_md_hmac_starts(&hmac_ctx, U2F->device_key, sizeof(U2F->device_key))); - // Generate private key handle - hmac_sha256_init(&hmac_ctx, U2F->device_key); - hmac_sha256_update(&hmac_ctx, private, 32); - hmac_sha256_update(&hmac_ctx, req->app_id, 32); - hmac_sha256_finish(&hmac_ctx, U2F->device_key, handle.hash); + // Generate private key + MCHECK(mbedtls_md_hmac_update(&hmac_ctx, req->app_id, sizeof(req->app_id))); + MCHECK(mbedtls_md_hmac_update(&hmac_ctx, handle.nonce, sizeof(handle.nonce))); + MCHECK(mbedtls_md_hmac_finish(&hmac_ctx, private)); + + MCHECK(mbedtls_md_hmac_reset(&hmac_ctx)); + + // Generate private key handle + MCHECK(mbedtls_md_hmac_update(&hmac_ctx, private, sizeof(private))); + MCHECK(mbedtls_md_hmac_update(&hmac_ctx, req->app_id, sizeof(req->app_id))); + MCHECK(mbedtls_md_hmac_finish(&hmac_ctx, handle.hash)); + } // Generate public key - pub_key.format = 0x04; // Uncompressed point - uECC_compute_public_key(private, pub_key.xy, U2F->p_curve); + u2f_ecc_compute_public_key(&U2F->group, private, &pub_key); // Generate signature - uint8_t reserved_byte = 0; - sha256_start(&sha_ctx); - sha256_update(&sha_ctx, &reserved_byte, 1); - sha256_update(&sha_ctx, req->app_id, 32); - sha256_update(&sha_ctx, req->challenge, 32); - sha256_update(&sha_ctx, handle.hash, handle.len); - sha256_update(&sha_ctx, (uint8_t*)&pub_key, 65); - sha256_finish(&sha_ctx, hash); + { + uint8_t reserved_byte = 0; + + mbedtls_sha256_context sha_ctx; + + mbedtls_sha256_init(&sha_ctx); + mbedtls_sha256_starts(&sha_ctx, 0); - uECC_sign(U2F->cert_key, hash, 32, signature, U2F->p_curve); + mbedtls_sha256_update(&sha_ctx, &reserved_byte, 1); + mbedtls_sha256_update(&sha_ctx, req->app_id, sizeof(req->app_id)); + mbedtls_sha256_update(&sha_ctx, req->challenge, sizeof(req->challenge)); + mbedtls_sha256_update(&sha_ctx, handle.hash, handle.len); + mbedtls_sha256_update(&sha_ctx, (uint8_t*)&pub_key, sizeof(U2fPubKey)); + + mbedtls_sha256_finish(&sha_ctx, hash); + mbedtls_sha256_free(&sha_ctx); + } + + // Sign hash + u2f_ecc_sign(&U2F->group, U2F->cert_key, hash, signature); // Encode response message resp->reserved = 0x05; @@ -250,13 +322,11 @@ static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) { static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { U2fAuthReq* req = (U2fAuthReq*)buf; U2fAuthResp* resp = (U2fAuthResp*)buf; - uint8_t priv_key[32]; + uint8_t priv_key[U2F_EC_KEY_SIZE]; uint8_t mac_control[32]; - hmac_sha256_context hmac_ctx; - sha256_context sha_ctx; uint8_t flags = 0; - uint8_t hash[32]; - uint8_t signature[64]; + uint8_t hash[U2F_HASH_SIZE]; + uint8_t signature[U2F_HASH_SIZE * 2]; uint32_t be_u2f_counter; if(u2f_data_check(false) == false) { @@ -281,26 +351,42 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { be_u2f_counter = lfs_tobe32(U2F->counter + 1); // Generate hash - sha256_start(&sha_ctx); - sha256_update(&sha_ctx, req->app_id, 32); - sha256_update(&sha_ctx, &flags, 1); - sha256_update(&sha_ctx, (uint8_t*)&(be_u2f_counter), 4); - sha256_update(&sha_ctx, req->challenge, 32); - sha256_finish(&sha_ctx, hash); - - // Recover private key - hmac_sha256_init(&hmac_ctx, U2F->device_key); - hmac_sha256_update(&hmac_ctx, req->app_id, 32); - hmac_sha256_update(&hmac_ctx, req->key_handle.nonce, 32); - hmac_sha256_finish(&hmac_ctx, U2F->device_key, priv_key); - - // Generate and verify private key handle - hmac_sha256_init(&hmac_ctx, U2F->device_key); - hmac_sha256_update(&hmac_ctx, priv_key, 32); - hmac_sha256_update(&hmac_ctx, req->app_id, 32); - hmac_sha256_finish(&hmac_ctx, U2F->device_key, mac_control); - - if(memcmp(req->key_handle.hash, mac_control, 32) != 0) { + { + mbedtls_sha256_context sha_ctx; + + mbedtls_sha256_init(&sha_ctx); + mbedtls_sha256_starts(&sha_ctx, 0); + + mbedtls_sha256_update(&sha_ctx, req->app_id, sizeof(req->app_id)); + mbedtls_sha256_update(&sha_ctx, &flags, 1); + mbedtls_sha256_update(&sha_ctx, (uint8_t*)&(be_u2f_counter), sizeof(be_u2f_counter)); + mbedtls_sha256_update(&sha_ctx, req->challenge, sizeof(req->challenge)); + + mbedtls_sha256_finish(&sha_ctx, hash); + mbedtls_sha256_free(&sha_ctx); + } + + { + mbedtls_md_context_t hmac_ctx; + mbedtls_md_init(&hmac_ctx); + MCHECK(mbedtls_md_setup(&hmac_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1)); + MCHECK(mbedtls_md_hmac_starts(&hmac_ctx, U2F->device_key, sizeof(U2F->device_key))); + + // Recover private key + MCHECK(mbedtls_md_hmac_update(&hmac_ctx, req->app_id, sizeof(req->app_id))); + MCHECK(mbedtls_md_hmac_update( + &hmac_ctx, req->key_handle.nonce, sizeof(req->key_handle.nonce))); + MCHECK(mbedtls_md_hmac_finish(&hmac_ctx, priv_key)); + + MCHECK(mbedtls_md_hmac_reset(&hmac_ctx)); + + // Generate and verify private key handle + MCHECK(mbedtls_md_hmac_update(&hmac_ctx, priv_key, sizeof(priv_key))); + MCHECK(mbedtls_md_hmac_update(&hmac_ctx, req->app_id, sizeof(req->app_id))); + MCHECK(mbedtls_md_hmac_finish(&hmac_ctx, mac_control)); + } + + if(memcmp(req->key_handle.hash, mac_control, sizeof(mac_control)) != 0) { FURI_LOG_W(TAG, "Wrong handle!"); memcpy(&buf[0], state_wrong_data, 2); return 2; @@ -311,7 +397,8 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { return 2; } - uECC_sign(priv_key, hash, 32, signature, U2F->p_curve); + // Sign hash + u2f_ecc_sign(&U2F->group, priv_key, hash, signature); resp->user_present = flags; resp->counter = be_u2f_counter; diff --git a/applications/main/u2f/u2f_data.c b/applications/main/u2f/u2f_data.c index 34360f3d639..cb9c4c2947d 100644 --- a/applications/main/u2f/u2f_data.c +++ b/applications/main/u2f/u2f_data.c @@ -37,7 +37,7 @@ typedef struct { uint32_t counter; uint8_t random_salt[24]; uint32_t control; -} __attribute__((packed)) U2fCounterData; +} FURI_PACKED U2fCounterData; bool u2f_data_check(bool cert_only) { bool state = false; diff --git a/applications/services/rpc/rpc_gui.c b/applications/services/rpc/rpc_gui.c index 9eff4bca6c5..ca8fc61a45f 100644 --- a/applications/services/rpc/rpc_gui.c +++ b/applications/services/rpc/rpc_gui.c @@ -1,9 +1,10 @@ -#include "flipper.pb.h" #include "rpc_i.h" -#include "gui.pb.h" #include #include +#include +#include + #define TAG "RpcGui" typedef enum { diff --git a/applications/services/rpc/rpc_i.h b/applications/services/rpc/rpc_i.h index 16e5e594d16..ffca50231c7 100644 --- a/applications/services/rpc/rpc_i.h +++ b/applications/services/rpc/rpc_i.h @@ -1,6 +1,6 @@ #pragma once #include "rpc.h" -#include "storage/filesystem_api_defines.h" +#include #include #include #include diff --git a/applications/services/rpc/rpc_storage.c b/applications/services/rpc/rpc_storage.c index 913d89f1afb..a934d1c31a1 100644 --- a/applications/services/rpc/rpc_storage.c +++ b/applications/services/rpc/rpc_storage.c @@ -1,18 +1,18 @@ -#include "flipper.pb.h" #include #include #include -#include "pb_decode.h" -#include "rpc/rpc.h" -#include "rpc_i.h" -#include "storage.pb.h" -#include "storage/filesystem_api_defines.h" -#include "storage/storage.h" -#include +#include +#include +#include +#include #include #include #include +#include +#include +#include + #define TAG "RpcStorage" #define MAX_NAME_LENGTH 255 diff --git a/applications/system/storage_move_to_sd/storage_move_to_sd.c b/applications/system/storage_move_to_sd/storage_move_to_sd.c index 25893f01106..5d1e694bca4 100644 --- a/applications/system/storage_move_to_sd/storage_move_to_sd.c +++ b/applications/system/storage_move_to_sd/storage_move_to_sd.c @@ -1,8 +1,8 @@ #include "storage_move_to_sd.h" + #include #include -#include "loader/loader.h" -#include +#include #include #include diff --git a/furi/core/common_defines.h b/furi/core/common_defines.h index 2b30c3b06da..b0062e65916 100644 --- a/furi/core/common_defines.h +++ b/furi/core/common_defines.h @@ -17,6 +17,10 @@ extern "C" { #define FURI_WEAK __attribute__((weak)) #endif +#ifndef FURI_PACKED +#define FURI_PACKED __attribute__((packed)) +#endif + #ifndef FURI_IS_IRQ_MASKED #define FURI_IS_IRQ_MASKED() (__get_PRIMASK() != 0U) #endif @@ -47,6 +51,10 @@ void __furi_critical_exit(__FuriCriticalInfo info); #define FURI_CRITICAL_EXIT() __furi_critical_exit(__furi_critical_info); #endif +#ifndef FURI_CHECK_RETURN +#define FURI_CHECK_RETURN __attribute__((__warn_unused_result__)) +#endif + #ifdef __cplusplus } #endif diff --git a/lib/ReadMe.md b/lib/ReadMe.md index 326d933aa5d..3adb7701877 100644 --- a/lib/ReadMe.md +++ b/lib/ReadMe.md @@ -11,7 +11,6 @@ - `fatfs` - FatFS file system driver - `flipper_application` - Flipper application library, used for FAPs - `flipper_format` - Flipper File Format library -- `fnv1a-hash` - FNV-1a hash library - `heatshrink` - Heatshrink compression library - `ibutton` - ibutton library, used by iButton application - `infrared` - Infrared library, used by Infrared application @@ -19,7 +18,6 @@ - `libusb_stm32` - LibUSB for STM32 series MCU - `littlefs` - LittleFS file system driver, used by internal storage - `mbedtls` - MbedTLS cryptography library -- `micro-ecc` - MicroECC cryptography library - `microtar` - MicroTAR library - `mlib` - M-Lib C containers library - `nanopb` - NanoPB library, protobuf implementation for MCU @@ -28,11 +26,10 @@ - `print` - Tiny printf implementation - `digital_signal` - Digital Signal library used by NFC for software implemented protocols - `pulse_reader` - Pulse Reader library used by NFC for software implemented protocols -- `qrcode` - QR-Code library - `stm32wb_cmsis` - STM32WB series CMSIS headers, extends CMSIS Core - `stm32wb_copro` - STM32WB Copro library: contains WPAN and radio co-processor firmware - `stm32wb_hal` - STM32WB HAL library, extends STM32WB CMSIS and provides HAL - `subghz` - Subghz library, used by SubGhz application -- `toolbox` - Toolbox library, contains various things that is used by flipper firmware +- `toolbox` - Toolbox library, contains various things that is used by Flipper firmware - `u8g2` - u8g2 graphics library, used by GUI subsystem - `update_util` - update utilities library, used by updater \ No newline at end of file diff --git a/lib/SConscript b/lib/SConscript index f2cc9d18a0d..4835724e09b 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -1,87 +1,24 @@ Import("env") -env.Append( - LINT_SOURCES=[ - Dir("app-scened-template"), - Dir("digital_signal"), - Dir("pulse_reader"), - Dir("signal_reader"), - Dir("drivers"), - Dir("flipper_format"), - Dir("infrared"), - Dir("nfc"), - Dir("subghz"), - Dir("toolbox"), - Dir("u8g2"), - Dir("update_util"), - Dir("print"), - Dir("music_worker"), - ], -) - env.Append( CPPPATH=[ "#/", "#/lib", # TODO FL-3553: remove! - "#/lib/mlib", # Ugly hack Dir("../assets/compiled"), ], - SDK_HEADERS=[ - *( - File(f"#/lib/mlib/m-{name}.h") - for name in ( - "algo", - "array", - "bptree", - "core", - "deque", - "dict", - "list", - "rbtree", - "tuple", - "variant", - ) - ), - ], - CPPDEFINES=[ - '"M_MEMORY_FULL(x)=abort()"', - ], ) -# drivers -# fatfs -# flipper_format -# infrared -# littlefs -# subghz -# toolbox -# one_wire -# micro-ecc -# misc -# digital_signal -# fnv1a_hash -# microtar -# nfc -# qrcode -# u8g2 -# update_util -# heatshrink -# nanopb -# apps -# app-scened-template -# callback-connector -# app-template - - libs = env.BuildModules( [ + "mlib", "stm32wb", "freertos", "print", "microtar", + "mbedtls", "toolbox", "libusb_stm32", "drivers", @@ -91,17 +28,19 @@ libs = env.BuildModules( "ibutton", "infrared", "littlefs", - "mbedtls", "subghz", "nfc", "digital_signal", "pulse_reader", "signal_reader", "appframe", - "misc", + "u8g2", "lfrfid", "flipper_application", "music_worker", + "nanopb", + "update_util", + "heatshrink", ], ) diff --git a/lib/appframe.scons b/lib/appframe.scons index 935986d644f..fb268579d66 100644 --- a/lib/appframe.scons +++ b/lib/appframe.scons @@ -5,6 +5,9 @@ env.Append( "#/lib/app-scened-template", "#/lib/callback-connector", ], + LINT_SOURCES=[ + Dir("app-scened-template"), + ], ) diff --git a/lib/digital_signal/SConscript b/lib/digital_signal/SConscript index b94c26f780a..41d33489047 100644 --- a/lib/digital_signal/SConscript +++ b/lib/digital_signal/SConscript @@ -8,6 +8,9 @@ env.Append( File("digital_signal.h"), File("digital_sequence.h"), ], + LINT_SOURCES=[ + Dir("."), + ], ) libenv = env.Clone(FW_LIB_NAME="digital_signal") diff --git a/lib/drivers/SConscript b/lib/drivers/SConscript index cf93d4bce98..a790d54a7a4 100644 --- a/lib/drivers/SConscript +++ b/lib/drivers/SConscript @@ -9,6 +9,9 @@ env.Append( File("st25r3916_reg.h"), File("st25r3916.h"), ], + LINT_SOURCES=[ + Dir("."), + ], ) diff --git a/lib/flipper_application/elf/elf_file.c b/lib/flipper_application/elf/elf_file.c index 8a78cca413d..65431686625 100644 --- a/lib/flipper_application/elf/elf_file.c +++ b/lib/flipper_application/elf/elf_file.c @@ -1,7 +1,8 @@ -#include "storage/storage.h" -#include #include "elf_file.h" #include "elf_file_i.h" + +#include +#include #include "elf_api_interface.h" #include "../api_hashtable/api_hashtable.h" @@ -34,7 +35,7 @@ const uint8_t trampoline_code_little_endian[TRAMPOLINE_CODE_SIZE] = typedef struct { uint8_t code[TRAMPOLINE_CODE_SIZE]; uint32_t addr; -} __attribute__((packed)) JMPTrampoline; +} FURI_PACKED JMPTrampoline; /**************************************************************************************************/ /********************************************* Caches *********************************************/ diff --git a/lib/flipper_format/SConscript b/lib/flipper_format/SConscript index 9c9e8b6f338..f16cd4f391c 100644 --- a/lib/flipper_format/SConscript +++ b/lib/flipper_format/SConscript @@ -9,6 +9,9 @@ env.Append( File("flipper_format_i.h"), File("flipper_format_stream.h"), ], + LINT_SOURCES=[ + Dir("."), + ], ) diff --git a/lib/fnv1a-hash/fnv1a-hash.c b/lib/fnv1a-hash/fnv1a-hash.c deleted file mode 100644 index 69c675f310a..00000000000 --- a/lib/fnv1a-hash/fnv1a-hash.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "fnv1a-hash.h" - -// FNV-1a hash, 32-bit -uint32_t fnv1a_buffer_hash(const uint8_t* buffer, uint32_t length, uint32_t hash) -{ - for (uint32_t i = 0; i < length; i++) { - hash = (hash ^ buffer[i]) * 16777619ULL; - } - return hash; -} diff --git a/lib/fnv1a-hash/fnv1a-hash.h b/lib/fnv1a-hash/fnv1a-hash.h deleted file mode 100644 index 3218cc27c75..00000000000 --- a/lib/fnv1a-hash/fnv1a-hash.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define FNV_1A_INIT 2166136261UL - -// FNV-1a hash, 32-bit -uint32_t fnv1a_buffer_hash(const uint8_t* buffer, uint32_t length, uint32_t hash); - -#ifdef __cplusplus -} -#endif - -#ifdef __cplusplus -// constexpr FNV-1a hash for strings, 32-bit -inline constexpr uint32_t fnv1a_string_hash(const char* str) { - uint32_t hash = FNV_1A_INIT; - - while(*str) { - hash = (hash ^ *str) * 16777619ULL; - str += 1; - } - return hash; -} -#else -// FNV-1a hash for strings, 32-bit -inline uint32_t fnv1a_string_hash(const char* str) { - uint32_t hash = FNV_1A_INIT; - - while(*str) { - hash = (hash ^ *str) * 16777619ULL; - str += 1; - } - return hash; -} -#endif diff --git a/lib/heatshrink.scons b/lib/heatshrink.scons new file mode 100644 index 00000000000..241b5a34e36 --- /dev/null +++ b/lib/heatshrink.scons @@ -0,0 +1,23 @@ +from fbt.util import GLOB_FILE_EXCLUSION + +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/heatshrink", + ], +) + + +libenv = env.Clone(FW_LIB_NAME="heatshrink") +libenv.ApplyLibFlags() + +sources = Glob( + "heatshrink/heatshrink_*.c*", + exclude=GLOB_FILE_EXCLUSION, + source=True, +) + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/infrared/SConscript b/lib/infrared/SConscript index 9a1543f00fa..a32248a645b 100644 --- a/lib/infrared/SConscript +++ b/lib/infrared/SConscript @@ -10,6 +10,9 @@ env.Append( File("worker/infrared_worker.h"), File("worker/infrared_transmit.h"), ], + LINT_SOURCES=[ + Dir("."), + ], ) diff --git a/lib/mbedtls b/lib/mbedtls index d65aeb37349..edb8fec9882 160000 --- a/lib/mbedtls +++ b/lib/mbedtls @@ -1 +1 @@ -Subproject commit d65aeb37349ad1a50e0f6c9b694d4b5290d60e49 +Subproject commit edb8fec9882084344a314368ac7fd957a187519c diff --git a/lib/mbedtls.scons b/lib/mbedtls.scons index 79a4a25203f..77add769668 100644 --- a/lib/mbedtls.scons +++ b/lib/mbedtls.scons @@ -2,13 +2,21 @@ Import("env") env.Append( CPPPATH=[ - "#/lib/mbedtls", + # "#/lib/mbedtls", "#/lib/mbedtls/include", ], SDK_HEADERS=[ File("mbedtls/include/mbedtls/des.h"), File("mbedtls/include/mbedtls/sha1.h"), + File("mbedtls/include/mbedtls/sha256.h"), + File("mbedtls/include/mbedtls/md5.h"), + File("mbedtls/include/mbedtls/md.h"), + File("mbedtls/include/mbedtls/ecdsa.h"), + File("mbedtls/include/mbedtls/ecdh.h"), + File("mbedtls/include/mbedtls/ecp.h"), + # File("mbedtls/include/mbedtls/sha1.h"), ], + CPPDEFINES=[("MBEDTLS_CONFIG_FILE", '\\"mbedtls_cfg.h\\"')], ) @@ -20,14 +28,30 @@ libenv.AppendUnique( # Required for lib to be linkable with .faps "-mword-relocations", "-mlong-calls", + # Crappy code :) + "-Wno-redundant-decls", ], ) +# If we were to build full mbedtls, we would need to use this: +# sources = libenv.GlobRecursive("*.c*", "mbedtls/library") +# Otherwise, we can just use the files we need: sources = [ - "mbedtls/library/des.c", - "mbedtls/library/sha1.c", - "mbedtls/library/platform_util.c", + File("mbedtls/library/bignum.c"), + File("mbedtls/library/bignum_core.c"), + File("mbedtls/library/ecdsa.c"), + File("mbedtls/library/ecp.c"), + File("mbedtls/library/ecp_curves.c"), + File("mbedtls/library/md.c"), + File("mbedtls/library/md5.c"), + File("mbedtls/library/platform_util.c"), + File("mbedtls/library/ripemd160.c"), + File("mbedtls/library/sha1.c"), + File("mbedtls/library/sha256.c"), + File("mbedtls/library/des.c"), ] +Depends(sources, File("mbedtls_cfg.h")) + lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) diff --git a/lib/mbedtls_cfg.h b/lib/mbedtls_cfg.h new file mode 100644 index 00000000000..5af98e96575 --- /dev/null +++ b/lib/mbedtls_cfg.h @@ -0,0 +1,92 @@ +#pragma once + +/** +* A subset of the mbedTLS configuration options that are relevant to the +* Flipper Zero firmware and apps. They are built to "mbedtls" library you can +* link your apps with. +* +* If you need more features, either bring the full mbedtls library into your +* app using "fap_private_libs" or open an issue on GitHub to add them to the +* default configuration. +**/ + +#define MBEDTLS_HAVE_ASM + +#define MBEDTLS_NO_UDBL_DIVISION +#define MBEDTLS_NO_64BIT_MULTIPLICATION + +#define MBEDTLS_DEPRECATED_WARNING + +#define MBEDTLS_AES_FEWER_TABLES +// #define MBEDTLS_CHECK_RETURN_WARNING + +#define MBEDTLS_CIPHER_MODE_CBC +#define MBEDTLS_CIPHER_MODE_CFB +#define MBEDTLS_CIPHER_MODE_CTR +#define MBEDTLS_CIPHER_MODE_OFB +#define MBEDTLS_CIPHER_MODE_XTS + +#define MBEDTLS_CIPHER_PADDING_PKCS7 +#define MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +#define MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +#define MBEDTLS_CIPHER_PADDING_ZEROS + +/* Short Weierstrass curves (supporting ECP, ECDH, ECDSA) */ +// #define MBEDTLS_ECP_DP_SECP192R1_ENABLED +// #define MBEDTLS_ECP_DP_SECP224R1_ENABLED +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +// #define MBEDTLS_ECP_DP_SECP384R1_ENABLED +// #define MBEDTLS_ECP_DP_SECP521R1_ENABLED +// #define MBEDTLS_ECP_DP_SECP192K1_ENABLED +// #define MBEDTLS_ECP_DP_SECP224K1_ENABLED +// #define MBEDTLS_ECP_DP_SECP256K1_ENABLED +// #define MBEDTLS_ECP_DP_BP256R1_ENABLED +// #define MBEDTLS_ECP_DP_BP384R1_ENABLED +// #define MBEDTLS_ECP_DP_BP512R1_ENABLED +/* Montgomery curves (supporting ECP) */ +// #define MBEDTLS_ECP_DP_CURVE25519_ENABLED +// #define MBEDTLS_ECP_DP_CURVE448_ENABLED + +#define MBEDTLS_ECP_NIST_OPTIM + +#define MBEDTLS_GENPRIME +// #define MBEDTLS_PKCS1_V15 +// #define MBEDTLS_PKCS1_V21 + +#define MBEDTLS_MD_C + +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C +#define MBEDTLS_BASE64_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_OID_C + +// #define MBEDTLS_CHACHA20_C +// #define MBEDTLS_CHACHAPOLY_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_DES_C +#define MBEDTLS_DHM_C + +#define MBEDTLS_ECDH_C + +#define MBEDTLS_ECDSA_C +#define MBEDTLS_ECP_C + +#define MBEDTLS_GCM_C + +#define MBEDTLS_AES_C +#define MBEDTLS_MD5_C + +// #define MBEDTLS_PEM_PARSE_C +// #define MBEDTLS_PEM_WRITE_C + +// #define MBEDTLS_PLATFORM_MEMORY +// #define MBEDTLS_PLATFORM_C + +// #define MBEDTLS_RIPEMD160_C +// #define MBEDTLS_RSA_C +#define MBEDTLS_SHA224_C +#define MBEDTLS_SHA256_C +#define MBEDTLS_SHA1_C + +#define MBEDTLS_ERROR_C \ No newline at end of file diff --git a/lib/micro-ecc/LICENSE.txt b/lib/micro-ecc/LICENSE.txt deleted file mode 100644 index ab099ae5a51..00000000000 --- a/lib/micro-ecc/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -Copyright (c) 2014, Kenneth MacKay -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/micro-ecc/README.md b/lib/micro-ecc/README.md deleted file mode 100644 index 111321bf765..00000000000 --- a/lib/micro-ecc/README.md +++ /dev/null @@ -1,41 +0,0 @@ -micro-ecc -========== - -A small and fast ECDH and ECDSA implementation for 8-bit, 32-bit, and 64-bit processors. - -The static version of micro-ecc (ie, where the curve was selected at compile-time) can be found in the "static" branch. - -Features --------- - - * Resistant to known side-channel attacks. - * Written in C, with optional GCC inline assembly for AVR, ARM and Thumb platforms. - * Supports 8, 32, and 64-bit architectures. - * Small code size. - * No dynamic memory allocation. - * Support for 5 standard curves: secp160r1, secp192r1, secp224r1, secp256r1, and secp256k1. - * BSD 2-clause license. - -Usage Notes ------------ -### Point Representation ### -Compressed points are represented in the standard format as defined in http://www.secg.org/sec1-v2.pdf; uncompressed points are represented in standard format, but without the `0x04` prefix. All functions except `uECC_decompress()` only accept uncompressed points; use `uECC_compress()` and `uECC_decompress()` to convert between compressed and uncompressed point representations. - -Private keys are represented in the standard format. - -### Using the Code ### - -I recommend just copying (or symlink) the uECC files into your project. Then just `#include "uECC.h"` to use the micro-ecc functions. - -For use with Arduino, you can use the Library Manager to download micro-ecc (**Sketch**=>**Include Library**=>**Manage Libraries**). You can then use uECC just like any other Arduino library (uECC should show up in the **Sketch**=>**Import Library** submenu). - -See uECC.h for documentation for each function. - -### Compilation Notes ### - - * Should compile with any C/C++ compiler that supports stdint.h (this includes Visual Studio 2013). - * If you want to change the defaults for any of the uECC compile-time options (such as `uECC_OPTIMIZATION_LEVEL`), you must change them in your Makefile or similar so that uECC.c is compiled with the desired values (ie, compile uECC.c with `-DuECC_OPTIMIZATION_LEVEL=3` or whatever). - * When compiling for a Thumb-1 platform, you must use the `-fomit-frame-pointer` GCC option (this is enabled by default when compiling with `-O1` or higher). - * When compiling for an ARM/Thumb-2 platform with `uECC_OPTIMIZATION_LEVEL` >= 3, you must use the `-fomit-frame-pointer` GCC option (this is enabled by default when compiling with `-O1` or higher). - * When compiling for AVR, you must have optimizations enabled (compile with `-O1` or higher). - * When building for Windows, you will need to link in the `advapi32.lib` system library. diff --git a/lib/micro-ecc/asm_arm.inc b/lib/micro-ecc/asm_arm.inc deleted file mode 100644 index 43844da6a56..00000000000 --- a/lib/micro-ecc/asm_arm.inc +++ /dev/null @@ -1,821 +0,0 @@ -/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ - -#ifndef _UECC_ASM_ARM_H_ -#define _UECC_ASM_ARM_H_ - -#if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1) - #define uECC_MIN_WORDS 8 -#endif -#if uECC_SUPPORTS_secp224r1 - #undef uECC_MIN_WORDS - #define uECC_MIN_WORDS 7 -#endif -#if uECC_SUPPORTS_secp192r1 - #undef uECC_MIN_WORDS - #define uECC_MIN_WORDS 6 -#endif -#if uECC_SUPPORTS_secp160r1 - #undef uECC_MIN_WORDS - #define uECC_MIN_WORDS 5 -#endif - -#if (uECC_PLATFORM == uECC_arm_thumb) - #define REG_RW "+l" - #define REG_WRITE "=l" -#else - #define REG_RW "+r" - #define REG_WRITE "=r" -#endif - -#if (uECC_PLATFORM == uECC_arm_thumb || uECC_PLATFORM == uECC_arm_thumb2) - #define REG_RW_LO "+l" - #define REG_WRITE_LO "=l" -#else - #define REG_RW_LO "+r" - #define REG_WRITE_LO "=r" -#endif - -#if (uECC_PLATFORM == uECC_arm_thumb2) - #define RESUME_SYNTAX -#else - #define RESUME_SYNTAX ".syntax divided \n\t" -#endif - -#if (uECC_OPTIMIZATION_LEVEL >= 2) - -uECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { -#if (uECC_MAX_WORDS != uECC_MIN_WORDS) - #if (uECC_PLATFORM == uECC_arm_thumb) || (uECC_PLATFORM == uECC_arm_thumb2) - uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 2 + 1; - #else /* ARM */ - uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 4; - #endif -#endif - uint32_t carry; - uint32_t left_word; - uint32_t right_word; - - __asm__ volatile ( - ".syntax unified \n\t" - "movs %[carry], #0 \n\t" - #if (uECC_MAX_WORDS != uECC_MIN_WORDS) - "adr %[left], 1f \n\t" - ".align 4 \n\t" - "adds %[jump], %[left] \n\t" - #endif - - "ldmia %[lptr]!, {%[left]} \n\t" - "ldmia %[rptr]!, {%[right]} \n\t" - "adds %[left], %[right] \n\t" - "stmia %[dptr]!, {%[left]} \n\t" - - #if (uECC_MAX_WORDS != uECC_MIN_WORDS) - "bx %[jump] \n\t" - #endif - "1: \n\t" - REPEAT(DEC(uECC_MAX_WORDS), - "ldmia %[lptr]!, {%[left]} \n\t" - "ldmia %[rptr]!, {%[right]} \n\t" - "adcs %[left], %[right] \n\t" - "stmia %[dptr]!, {%[left]} \n\t") - - "adcs %[carry], %[carry] \n\t" - RESUME_SYNTAX - : [dptr] REG_RW_LO (result), [lptr] REG_RW_LO (left), [rptr] REG_RW_LO (right), - #if (uECC_MAX_WORDS != uECC_MIN_WORDS) - [jump] REG_RW_LO (jump), - #endif - [carry] REG_WRITE_LO (carry), [left] REG_WRITE_LO (left_word), - [right] REG_WRITE_LO (right_word) - : - : "cc", "memory" - ); - return carry; -} -#define asm_add 1 - -#pragma GCC diagnostic ignored "-Wredundant-decls" -uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { -#if (uECC_MAX_WORDS != uECC_MIN_WORDS) - #if (uECC_PLATFORM == uECC_arm_thumb) || (uECC_PLATFORM == uECC_arm_thumb2) - uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 2 + 1; - #else /* ARM */ - uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 4; - #endif -#endif - uint32_t carry; - uint32_t left_word; - uint32_t right_word; - - __asm__ volatile ( - ".syntax unified \n\t" - "movs %[carry], #0 \n\t" - #if (uECC_MAX_WORDS != uECC_MIN_WORDS) - "adr %[left], 1f \n\t" - ".align 4 \n\t" - "adds %[jump], %[left] \n\t" - #endif - - "ldmia %[lptr]!, {%[left]} \n\t" - "ldmia %[rptr]!, {%[right]} \n\t" - "subs %[left], %[right] \n\t" - "stmia %[dptr]!, {%[left]} \n\t" - - #if (uECC_MAX_WORDS != uECC_MIN_WORDS) - "bx %[jump] \n\t" - #endif - "1: \n\t" - REPEAT(DEC(uECC_MAX_WORDS), - "ldmia %[lptr]!, {%[left]} \n\t" - "ldmia %[rptr]!, {%[right]} \n\t" - "sbcs %[left], %[right] \n\t" - "stmia %[dptr]!, {%[left]} \n\t") - - "adcs %[carry], %[carry] \n\t" - RESUME_SYNTAX - : [dptr] REG_RW_LO (result), [lptr] REG_RW_LO (left), [rptr] REG_RW_LO (right), - #if (uECC_MAX_WORDS != uECC_MIN_WORDS) - [jump] REG_RW_LO (jump), - #endif - [carry] REG_WRITE_LO (carry), [left] REG_WRITE_LO (left_word), - [right] REG_WRITE_LO (right_word) - : - : "cc", "memory" - ); - return !carry; /* Note that on ARM, carry flag set means "no borrow" when subtracting - (for some reason...) */ -} -#define asm_sub 1 - -#endif /* (uECC_OPTIMIZATION_LEVEL >= 2) */ - -#if (uECC_OPTIMIZATION_LEVEL >= 3) - -#if (uECC_PLATFORM != uECC_arm_thumb) - -#if uECC_ARM_USE_UMAAL - #include "asm_arm_mult_square_umaal.inc" -#else - #include "asm_arm_mult_square.inc" -#endif - -#if (uECC_OPTIMIZATION_LEVEL == 3) - -uECC_VLI_API void uECC_vli_mult(uint32_t *result, - const uint32_t *left, - const uint32_t *right, - wordcount_t num_words) { - register uint32_t *r0 __asm__("r0") = result; - register const uint32_t *r1 __asm__("r1") = left; - register const uint32_t *r2 __asm__("r2") = right; - register uint32_t r3 __asm__("r3") = num_words; - - __asm__ volatile ( - ".syntax unified \n\t" -#if (uECC_MIN_WORDS == 5) - FAST_MULT_ASM_5 - #if (uECC_MAX_WORDS > 5) - FAST_MULT_ASM_5_TO_6 - #endif - #if (uECC_MAX_WORDS > 6) - FAST_MULT_ASM_6_TO_7 - #endif - #if (uECC_MAX_WORDS > 7) - FAST_MULT_ASM_7_TO_8 - #endif -#elif (uECC_MIN_WORDS == 6) - FAST_MULT_ASM_6 - #if (uECC_MAX_WORDS > 6) - FAST_MULT_ASM_6_TO_7 - #endif - #if (uECC_MAX_WORDS > 7) - FAST_MULT_ASM_7_TO_8 - #endif -#elif (uECC_MIN_WORDS == 7) - FAST_MULT_ASM_7 - #if (uECC_MAX_WORDS > 7) - FAST_MULT_ASM_7_TO_8 - #endif -#elif (uECC_MIN_WORDS == 8) - FAST_MULT_ASM_8 -#endif - "1: \n\t" - RESUME_SYNTAX - : "+r" (r0), "+r" (r1), "+r" (r2) - : "r" (r3) - : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); -} -#define asm_mult 1 - -#if uECC_SQUARE_FUNC -uECC_VLI_API void uECC_vli_square(uECC_word_t *result, - const uECC_word_t *left, - wordcount_t num_words) { - register uint32_t *r0 __asm__("r0") = result; - register const uint32_t *r1 __asm__("r1") = left; - register uint32_t r2 __asm__("r2") = num_words; - - __asm__ volatile ( - ".syntax unified \n\t" -#if (uECC_MIN_WORDS == 5) - FAST_SQUARE_ASM_5 - #if (uECC_MAX_WORDS > 5) - FAST_SQUARE_ASM_5_TO_6 - #endif - #if (uECC_MAX_WORDS > 6) - FAST_SQUARE_ASM_6_TO_7 - #endif - #if (uECC_MAX_WORDS > 7) - FAST_SQUARE_ASM_7_TO_8 - #endif -#elif (uECC_MIN_WORDS == 6) - FAST_SQUARE_ASM_6 - #if (uECC_MAX_WORDS > 6) - FAST_SQUARE_ASM_6_TO_7 - #endif - #if (uECC_MAX_WORDS > 7) - FAST_SQUARE_ASM_7_TO_8 - #endif -#elif (uECC_MIN_WORDS == 7) - FAST_SQUARE_ASM_7 - #if (uECC_MAX_WORDS > 7) - FAST_SQUARE_ASM_7_TO_8 - #endif -#elif (uECC_MIN_WORDS == 8) - FAST_SQUARE_ASM_8 -#endif - - "1: \n\t" - RESUME_SYNTAX - : "+r" (r0), "+r" (r1) - : "r" (r2) - : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); -} -#define asm_square 1 -#endif /* uECC_SQUARE_FUNC */ - -#else /* (uECC_OPTIMIZATION_LEVEL > 3) */ - -uECC_VLI_API void uECC_vli_mult(uint32_t *result, - const uint32_t *left, - const uint32_t *right, - wordcount_t num_words) { - register uint32_t *r0 __asm__("r0") = result; - register const uint32_t *r1 __asm__("r1") = left; - register const uint32_t *r2 __asm__("r2") = right; - register uint32_t r3 __asm__("r3") = num_words; - -#if uECC_SUPPORTS_secp160r1 - if (num_words == 5) { - __asm__ volatile ( - ".syntax unified \n\t" - FAST_MULT_ASM_5 - RESUME_SYNTAX - : "+r" (r0), "+r" (r1), "+r" (r2) - : "r" (r3) - : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); - return; - } -#endif -#if uECC_SUPPORTS_secp192r1 - if (num_words == 6) { - __asm__ volatile ( - ".syntax unified \n\t" - FAST_MULT_ASM_6 - RESUME_SYNTAX - : "+r" (r0), "+r" (r1), "+r" (r2) - : "r" (r3) - : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); - return; - } -#endif -#if uECC_SUPPORTS_secp224r1 - if (num_words == 7) { - __asm__ volatile ( - ".syntax unified \n\t" - FAST_MULT_ASM_7 - RESUME_SYNTAX - : "+r" (r0), "+r" (r1), "+r" (r2) - : "r" (r3) - : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); - return; - } -#endif -#if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1) - if (num_words == 8) { - __asm__ volatile ( - ".syntax unified \n\t" - FAST_MULT_ASM_8 - RESUME_SYNTAX - : "+r" (r0), "+r" (r1), "+r" (r2) - : "r" (r3) - : "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); - return; - } -#endif -} -#define asm_mult 1 - -#if uECC_SQUARE_FUNC -uECC_VLI_API void uECC_vli_square(uECC_word_t *result, - const uECC_word_t *left, - wordcount_t num_words) { - register uint32_t *r0 __asm__("r0") = result; - register const uint32_t *r1 __asm__("r1") = left; - register uint32_t r2 __asm__("r2") = num_words; - -#if uECC_SUPPORTS_secp160r1 - if (num_words == 5) { - __asm__ volatile ( - ".syntax unified \n\t" - FAST_SQUARE_ASM_5 - RESUME_SYNTAX - : "+r" (r0), "+r" (r1) - : "r" (r2) - : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); - return; - } -#endif -#if uECC_SUPPORTS_secp192r1 - if (num_words == 6) { - __asm__ volatile ( - ".syntax unified \n\t" - FAST_SQUARE_ASM_6 - RESUME_SYNTAX - : "+r" (r0), "+r" (r1) - : "r" (r2) - : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); - return; - } -#endif -#if uECC_SUPPORTS_secp224r1 - if (num_words == 7) { - __asm__ volatile ( - ".syntax unified \n\t" - FAST_SQUARE_ASM_7 - RESUME_SYNTAX - : "+r" (r0), "+r" (r1) - : "r" (r2) - : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); - return; - } -#endif -#if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1) - if (num_words == 8) { - __asm__ volatile ( - ".syntax unified \n\t" - FAST_SQUARE_ASM_8 - RESUME_SYNTAX - : "+r" (r0), "+r" (r1) - : "r" (r2) - : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); - return; - } -#endif -} -#define asm_square 1 -#endif /* uECC_SQUARE_FUNC */ - -#endif /* (uECC_OPTIMIZATION_LEVEL > 3) */ - -#endif /* uECC_PLATFORM != uECC_arm_thumb */ - -#endif /* (uECC_OPTIMIZATION_LEVEL >= 3) */ - -/* ---- "Small" implementations ---- */ - -#if !asm_add -uECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { - uint32_t carry = 0; - uint32_t left_word; - uint32_t right_word; - - __asm__ volatile ( - ".syntax unified \n\t" - "1: \n\t" - "ldmia %[lptr]!, {%[left]} \n\t" /* Load left word. */ - "ldmia %[rptr]!, {%[right]} \n\t" /* Load right word. */ - "lsrs %[carry], #1 \n\t" /* Set up carry flag (carry = 0 after this). */ - "adcs %[left], %[left], %[right] \n\t" /* Add with carry. */ - "adcs %[carry], %[carry], %[carry] \n\t" /* Store carry bit. */ - "stmia %[dptr]!, {%[left]} \n\t" /* Store result word. */ - "subs %[ctr], #1 \n\t" /* Decrement counter. */ - "bne 1b \n\t" /* Loop until counter == 0. */ - RESUME_SYNTAX - : [dptr] REG_RW (result), [lptr] REG_RW (left), [rptr] REG_RW (right), - [ctr] REG_RW (num_words), [carry] REG_RW (carry), - [left] REG_WRITE (left_word), [right] REG_WRITE (right_word) - : - : "cc", "memory" - ); - return carry; -} -#define asm_add 1 -#endif - -#if !asm_sub -uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { - uint32_t carry = 1; /* carry = 1 initially (means don't borrow) */ - uint32_t left_word; - uint32_t right_word; - - __asm__ volatile ( - ".syntax unified \n\t" - "1: \n\t" - "ldmia %[lptr]!, {%[left]} \n\t" /* Load left word. */ - "ldmia %[rptr]!, {%[right]} \n\t" /* Load right word. */ - "lsrs %[carry], #1 \n\t" /* Set up carry flag (carry = 0 after this). */ - "sbcs %[left], %[left], %[right] \n\t" /* Subtract with borrow. */ - "adcs %[carry], %[carry], %[carry] \n\t" /* Store carry bit. */ - "stmia %[dptr]!, {%[left]} \n\t" /* Store result word. */ - "subs %[ctr], #1 \n\t" /* Decrement counter. */ - "bne 1b \n\t" /* Loop until counter == 0. */ - RESUME_SYNTAX - : [dptr] REG_RW (result), [lptr] REG_RW (left), [rptr] REG_RW (right), - [ctr] REG_RW (num_words), [carry] REG_RW (carry), - [left] REG_WRITE (left_word), [right] REG_WRITE (right_word) - : - : "cc", "memory" - ); - return !carry; -} -#define asm_sub 1 -#endif - -#if !asm_mult -uECC_VLI_API void uECC_vli_mult(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { -#if (uECC_PLATFORM != uECC_arm_thumb) - uint32_t c0 = 0; - uint32_t c1 = 0; - uint32_t c2 = 0; - uint32_t k = 0; - uint32_t i; - uint32_t t0, t1; - - __asm__ volatile ( - ".syntax unified \n\t" - - "1: \n\t" /* outer loop (k < num_words) */ - "movs %[i], #0 \n\t" /* i = 0 */ - "b 3f \n\t" - - "2: \n\t" /* outer loop (k >= num_words) */ - "movs %[i], %[k] \n\t" /* i = k */ - "subs %[i], %[last_word] \n\t" /* i = k - (num_words - 1) (times 4) */ - - "3: \n\t" /* inner loop */ - "subs %[t0], %[k], %[i] \n\t" /* t0 = k-i */ - - "ldr %[t1], [%[right], %[t0]] \n\t" /* t1 = right[k - i] */ - "ldr %[t0], [%[left], %[i]] \n\t" /* t0 = left[i] */ - - "umull %[t0], %[t1], %[t0], %[t1] \n\t" /* (t0, t1) = left[i] * right[k - i] */ - - "adds %[c0], %[c0], %[t0] \n\t" /* add low word to c0 */ - "adcs %[c1], %[c1], %[t1] \n\t" /* add high word to c1, including carry */ - "adcs %[c2], %[c2], #0 \n\t" /* add carry to c2 */ - - "adds %[i], #4 \n\t" /* i += 4 */ - "cmp %[i], %[last_word] \n\t" /* i > (num_words - 1) (times 4)? */ - "bgt 4f \n\t" /* if so, exit the loop */ - "cmp %[i], %[k] \n\t" /* i <= k? */ - "ble 3b \n\t" /* if so, continue looping */ - - "4: \n\t" /* end inner loop */ - - "str %[c0], [%[result], %[k]] \n\t" /* result[k] = c0 */ - "mov %[c0], %[c1] \n\t" /* c0 = c1 */ - "mov %[c1], %[c2] \n\t" /* c1 = c2 */ - "movs %[c2], #0 \n\t" /* c2 = 0 */ - "adds %[k], #4 \n\t" /* k += 4 */ - "cmp %[k], %[last_word] \n\t" /* k <= (num_words - 1) (times 4) ? */ - "ble 1b \n\t" /* if so, loop back, start with i = 0 */ - "cmp %[k], %[last_word], lsl #1 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */ - "ble 2b \n\t" /* if so, loop back, start with i = (k + 1) - num_words */ - /* end outer loop */ - - "str %[c0], [%[result], %[k]] \n\t" /* result[num_words * 2 - 1] = c0 */ - RESUME_SYNTAX - : [c0] "+r" (c0), [c1] "+r" (c1), [c2] "+r" (c2), - [k] "+r" (k), [i] "=&r" (i), [t0] "=&r" (t0), [t1] "=&r" (t1) - : [result] "r" (result), [left] "r" (left), [right] "r" (right), - [last_word] "r" ((num_words - 1) * 4) - : "cc", "memory" - ); - -#else /* Thumb-1 */ - uint32_t r4, r5, r6, r7; - - __asm__ volatile ( - ".syntax unified \n\t" - "subs %[r3], #1 \n\t" /* r3 = num_words - 1 */ - "lsls %[r3], #2 \n\t" /* r3 = (num_words - 1) * 4 */ - "mov r8, %[r3] \n\t" /* r8 = (num_words - 1) * 4 */ - "lsls %[r3], #1 \n\t" /* r3 = (num_words - 1) * 8 */ - "mov r9, %[r3] \n\t" /* r9 = (num_words - 1) * 8 */ - "movs %[r3], #0 \n\t" /* c0 = 0 */ - "movs %[r4], #0 \n\t" /* c1 = 0 */ - "movs %[r5], #0 \n\t" /* c2 = 0 */ - "movs %[r6], #0 \n\t" /* k = 0 */ - - "push {%[r0]} \n\t" /* keep result on the stack */ - - "1: \n\t" /* outer loop (k < num_words) */ - "movs %[r7], #0 \n\t" /* r7 = i = 0 */ - "b 3f \n\t" - - "2: \n\t" /* outer loop (k >= num_words) */ - "movs %[r7], %[r6] \n\t" /* r7 = k */ - "mov %[r0], r8 \n\t" /* r0 = (num_words - 1) * 4 */ - "subs %[r7], %[r0] \n\t" /* r7 = i = k - (num_words - 1) (times 4) */ - - "3: \n\t" /* inner loop */ - "mov r10, %[r3] \n\t" - "mov r11, %[r4] \n\t" - "mov r12, %[r5] \n\t" - "mov r14, %[r6] \n\t" - "subs %[r0], %[r6], %[r7] \n\t" /* r0 = k - i */ - - "ldr %[r4], [%[r2], %[r0]] \n\t" /* r4 = right[k - i] */ - "ldr %[r0], [%[r1], %[r7]] \n\t" /* r0 = left[i] */ - - "lsrs %[r3], %[r0], #16 \n\t" /* r3 = a1 */ - "uxth %[r0], %[r0] \n\t" /* r0 = a0 */ - - "lsrs %[r5], %[r4], #16 \n\t" /* r5 = b1 */ - "uxth %[r4], %[r4] \n\t" /* r4 = b0 */ - - "movs %[r6], %[r3] \n\t" /* r6 = a1 */ - "muls %[r6], %[r5], %[r6] \n\t" /* r6 = a1 * b1 */ - "muls %[r3], %[r4], %[r3] \n\t" /* r3 = b0 * a1 */ - "muls %[r5], %[r0], %[r5] \n\t" /* r5 = a0 * b1 */ - "muls %[r0], %[r4], %[r0] \n\t" /* r0 = a0 * b0 */ - - /* Add middle terms */ - "lsls %[r4], %[r3], #16 \n\t" - "lsrs %[r3], %[r3], #16 \n\t" - "adds %[r0], %[r4] \n\t" - "adcs %[r6], %[r3] \n\t" - - "lsls %[r4], %[r5], #16 \n\t" - "lsrs %[r5], %[r5], #16 \n\t" - "adds %[r0], %[r4] \n\t" - "adcs %[r6], %[r5] \n\t" - - "mov %[r3], r10\n\t" - "mov %[r4], r11\n\t" - "mov %[r5], r12\n\t" - "adds %[r3], %[r0] \n\t" /* add low word to c0 */ - "adcs %[r4], %[r6] \n\t" /* add high word to c1, including carry */ - "movs %[r0], #0 \n\t" /* r0 = 0 (does not affect carry bit) */ - "adcs %[r5], %[r0] \n\t" /* add carry to c2 */ - - "mov %[r6], r14\n\t" /* r6 = k */ - - "adds %[r7], #4 \n\t" /* i += 4 */ - "cmp %[r7], r8 \n\t" /* i > (num_words - 1) (times 4)? */ - "bgt 4f \n\t" /* if so, exit the loop */ - "cmp %[r7], %[r6] \n\t" /* i <= k? */ - "ble 3b \n\t" /* if so, continue looping */ - - "4: \n\t" /* end inner loop */ - - "ldr %[r0], [sp, #0] \n\t" /* r0 = result */ - - "str %[r3], [%[r0], %[r6]] \n\t" /* result[k] = c0 */ - "mov %[r3], %[r4] \n\t" /* c0 = c1 */ - "mov %[r4], %[r5] \n\t" /* c1 = c2 */ - "movs %[r5], #0 \n\t" /* c2 = 0 */ - "adds %[r6], #4 \n\t" /* k += 4 */ - "cmp %[r6], r8 \n\t" /* k <= (num_words - 1) (times 4) ? */ - "ble 1b \n\t" /* if so, loop back, start with i = 0 */ - "cmp %[r6], r9 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */ - "ble 2b \n\t" /* if so, loop back, with i = (k + 1) - num_words */ - /* end outer loop */ - - "str %[r3], [%[r0], %[r6]] \n\t" /* result[num_words * 2 - 1] = c0 */ - "pop {%[r0]} \n\t" /* pop result off the stack */ - - ".syntax divided \n\t" - : [r3] "+l" (num_words), [r4] "=&l" (r4), - [r5] "=&l" (r5), [r6] "=&l" (r6), [r7] "=&l" (r7) - : [r0] "l" (result), [r1] "l" (left), [r2] "l" (right) - : "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); -#endif -} -#define asm_mult 1 -#endif - -#if uECC_SQUARE_FUNC -#if !asm_square -uECC_VLI_API void uECC_vli_square(uECC_word_t *result, - const uECC_word_t *left, - wordcount_t num_words) { -#if (uECC_PLATFORM != uECC_arm_thumb) - uint32_t c0 = 0; - uint32_t c1 = 0; - uint32_t c2 = 0; - uint32_t k = 0; - uint32_t i, tt; - uint32_t t0, t1; - - __asm__ volatile ( - ".syntax unified \n\t" - - "1: \n\t" /* outer loop (k < num_words) */ - "movs %[i], #0 \n\t" /* i = 0 */ - "b 3f \n\t" - - "2: \n\t" /* outer loop (k >= num_words) */ - "movs %[i], %[k] \n\t" /* i = k */ - "subs %[i], %[last_word] \n\t" /* i = k - (num_words - 1) (times 4) */ - - "3: \n\t" /* inner loop */ - "subs %[tt], %[k], %[i] \n\t" /* tt = k-i */ - - "ldr %[t1], [%[left], %[tt]] \n\t" /* t1 = left[k - i] */ - "ldr %[t0], [%[left], %[i]] \n\t" /* t0 = left[i] */ - - "umull %[t0], %[t1], %[t0], %[t1] \n\t" /* (t0, t1) = left[i] * right[k - i] */ - - "cmp %[i], %[tt] \n\t" /* (i < k - i) ? */ - "bge 4f \n\t" /* if i >= k - i, skip */ - "adds %[c0], %[c0], %[t0] \n\t" /* add low word to c0 */ - "adcs %[c1], %[c1], %[t1] \n\t" /* add high word to c1, including carry */ - "adcs %[c2], %[c2], #0 \n\t" /* add carry to c2 */ - - "4: \n\t" - "adds %[c0], %[c0], %[t0] \n\t" /* add low word to c0 */ - "adcs %[c1], %[c1], %[t1] \n\t" /* add high word to c1, including carry */ - "adcs %[c2], %[c2], #0 \n\t" /* add carry to c2 */ - - "adds %[i], #4 \n\t" /* i += 4 */ - "cmp %[i], %[k] \n\t" /* i >= k? */ - "bge 5f \n\t" /* if so, exit the loop */ - "subs %[tt], %[k], %[i] \n\t" /* tt = k - i */ - "cmp %[i], %[tt] \n\t" /* i <= k - i? */ - "ble 3b \n\t" /* if so, continue looping */ - - "5: \n\t" /* end inner loop */ - - "str %[c0], [%[result], %[k]] \n\t" /* result[k] = c0 */ - "mov %[c0], %[c1] \n\t" /* c0 = c1 */ - "mov %[c1], %[c2] \n\t" /* c1 = c2 */ - "movs %[c2], #0 \n\t" /* c2 = 0 */ - "adds %[k], #4 \n\t" /* k += 4 */ - "cmp %[k], %[last_word] \n\t" /* k <= (num_words - 1) (times 4) ? */ - "ble 1b \n\t" /* if so, loop back, start with i = 0 */ - "cmp %[k], %[last_word], lsl #1 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */ - "ble 2b \n\t" /* if so, loop back, start with i = (k + 1) - num_words */ - /* end outer loop */ - - "str %[c0], [%[result], %[k]] \n\t" /* result[num_words * 2 - 1] = c0 */ - RESUME_SYNTAX - : [c0] "+r" (c0), [c1] "+r" (c1), [c2] "+r" (c2), - [k] "+r" (k), [i] "=&r" (i), [tt] "=&r" (tt), [t0] "=&r" (t0), [t1] "=&r" (t1) - : [result] "r" (result), [left] "r" (left), [last_word] "r" ((num_words - 1) * 4) - : "cc", "memory" - ); - -#else - uint32_t r3, r4, r5, r6, r7; - - __asm__ volatile ( - ".syntax unified \n\t" - "subs %[r2], #1 \n\t" /* r2 = num_words - 1 */ - "lsls %[r2], #2 \n\t" /* r2 = (num_words - 1) * 4 */ - "mov r8, %[r2] \n\t" /* r8 = (num_words - 1) * 4 */ - "lsls %[r2], #1 \n\t" /* r2 = (num_words - 1) * 8 */ - "mov r9, %[r2] \n\t" /* r9 = (num_words - 1) * 8 */ - "movs %[r2], #0 \n\t" /* c0 = 0 */ - "movs %[r3], #0 \n\t" /* c1 = 0 */ - "movs %[r4], #0 \n\t" /* c2 = 0 */ - "movs %[r5], #0 \n\t" /* k = 0 */ - - "push {%[r0]} \n\t" /* keep result on the stack */ - - "1: \n\t" /* outer loop (k < num_words) */ - "movs %[r6], #0 \n\t" /* r6 = i = 0 */ - "b 3f \n\t" - - "2: \n\t" /* outer loop (k >= num_words) */ - "movs %[r6], %[r5] \n\t" /* r6 = k */ - "mov %[r0], r8 \n\t" /* r0 = (num_words - 1) * 4 */ - "subs %[r6], %[r0] \n\t" /* r6 = i = k - (num_words - 1) (times 4) */ - - "3: \n\t" /* inner loop */ - "mov r10, %[r2] \n\t" - "mov r11, %[r3] \n\t" - "mov r12, %[r4] \n\t" - "mov r14, %[r5] \n\t" - "subs %[r7], %[r5], %[r6] \n\t" /* r7 = k - i */ - - "ldr %[r3], [%[r1], %[r7]] \n\t" /* r3 = left[k - i] */ - "ldr %[r0], [%[r1], %[r6]] \n\t" /* r0 = left[i] */ - - "lsrs %[r2], %[r0], #16 \n\t" /* r2 = a1 */ - "uxth %[r0], %[r0] \n\t" /* r0 = a0 */ - - "lsrs %[r4], %[r3], #16 \n\t" /* r4 = b1 */ - "uxth %[r3], %[r3] \n\t" /* r3 = b0 */ - - "movs %[r5], %[r2] \n\t" /* r5 = a1 */ - "muls %[r5], %[r4], %[r5] \n\t" /* r5 = a1 * b1 */ - "muls %[r2], %[r3], %[r2] \n\t" /* r2 = b0 * a1 */ - "muls %[r4], %[r0], %[r4] \n\t" /* r4 = a0 * b1 */ - "muls %[r0], %[r3], %[r0] \n\t" /* r0 = a0 * b0 */ - - /* Add middle terms */ - "lsls %[r3], %[r2], #16 \n\t" - "lsrs %[r2], %[r2], #16 \n\t" - "adds %[r0], %[r3] \n\t" - "adcs %[r5], %[r2] \n\t" - - "lsls %[r3], %[r4], #16 \n\t" - "lsrs %[r4], %[r4], #16 \n\t" - "adds %[r0], %[r3] \n\t" - "adcs %[r5], %[r4] \n\t" - - /* Add to acc, doubling if necessary */ - "mov %[r2], r10\n\t" - "mov %[r3], r11\n\t" - "mov %[r4], r12\n\t" - - "cmp %[r6], %[r7] \n\t" /* (i < k - i) ? */ - "bge 4f \n\t" /* if i >= k - i, skip */ - "movs %[r7], #0 \n\t" /* r7 = 0 */ - "adds %[r2], %[r0] \n\t" /* add low word to c0 */ - "adcs %[r3], %[r5] \n\t" /* add high word to c1, including carry */ - "adcs %[r4], %[r7] \n\t" /* add carry to c2 */ - "4: \n\t" - "movs %[r7], #0 \n\t" /* r7 = 0 */ - "adds %[r2], %[r0] \n\t" /* add low word to c0 */ - "adcs %[r3], %[r5] \n\t" /* add high word to c1, including carry */ - "adcs %[r4], %[r7] \n\t" /* add carry to c2 */ - - "mov %[r5], r14\n\t" /* r5 = k */ - - "adds %[r6], #4 \n\t" /* i += 4 */ - "cmp %[r6], %[r5] \n\t" /* i >= k? */ - "bge 5f \n\t" /* if so, exit the loop */ - "subs %[r7], %[r5], %[r6] \n\t" /* r7 = k - i */ - "cmp %[r6], %[r7] \n\t" /* i <= k - i? */ - "ble 3b \n\t" /* if so, continue looping */ - - "5: \n\t" /* end inner loop */ - - "ldr %[r0], [sp, #0] \n\t" /* r0 = result */ - - "str %[r2], [%[r0], %[r5]] \n\t" /* result[k] = c0 */ - "mov %[r2], %[r3] \n\t" /* c0 = c1 */ - "mov %[r3], %[r4] \n\t" /* c1 = c2 */ - "movs %[r4], #0 \n\t" /* c2 = 0 */ - "adds %[r5], #4 \n\t" /* k += 4 */ - "cmp %[r5], r8 \n\t" /* k <= (num_words - 1) (times 4) ? */ - "ble 1b \n\t" /* if so, loop back, start with i = 0 */ - "cmp %[r5], r9 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */ - "ble 2b \n\t" /* if so, loop back, with i = (k + 1) - num_words */ - /* end outer loop */ - - "str %[r2], [%[r0], %[r5]] \n\t" /* result[num_words * 2 - 1] = c0 */ - "pop {%[r0]} \n\t" /* pop result off the stack */ - - ".syntax divided \n\t" - : [r2] "+l" (num_words), [r3] "=&l" (r3), [r4] "=&l" (r4), - [r5] "=&l" (r5), [r6] "=&l" (r6), [r7] "=&l" (r7) - : [r0] "l" (result), [r1] "l" (left) - : "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory" - ); -#endif -} -#define asm_square 1 -#endif -#endif /* uECC_SQUARE_FUNC */ - -#endif /* _UECC_ASM_ARM_H_ */ diff --git a/lib/micro-ecc/asm_arm_mult_square.inc b/lib/micro-ecc/asm_arm_mult_square.inc deleted file mode 100644 index 8907fc1858d..00000000000 --- a/lib/micro-ecc/asm_arm_mult_square.inc +++ /dev/null @@ -1,2311 +0,0 @@ -/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ - -#ifndef _UECC_ASM_ARM_MULT_SQUARE_H_ -#define _UECC_ASM_ARM_MULT_SQUARE_H_ - -#define FAST_MULT_ASM_5 \ - "push {r3} \n\t" \ - "add r0, 12 \n\t" \ - "add r2, 12 \n\t" \ - "ldmia r1!, {r3,r4} \n\t" \ - "ldmia r2!, {r6,r7} \n\t" \ - \ - "umull r11, r12, r3, r6 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r9, r3, r7 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r14, r4, r6 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "umull r12, r14, r4, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adc r10, r10, r14 \n\t" \ - "stmia r0!, {r9, r10} \n\t" \ - \ - "sub r0, 28 \n\t" \ - "sub r2, 20 \n\t" \ - "ldmia r2!, {r6,r7,r8} \n\t" \ - "ldmia r1!, {r5} \n\t" \ - \ - "umull r11, r12, r3, r6 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r9, r3, r7 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r14, r4, r6 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r3, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r5, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "ldmia r1!, {r3} \n\t" \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r4, r8 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r5, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r3, r6 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "ldmia r1!, {r4} \n\t" \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r5, r8 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r3, r7 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r4, r6 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "ldr r9, [r0] \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, #0 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "ldmia r2!, {r6} \n\t" \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r5, r6 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r3, r8 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r4, r7 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "ldr r10, [r0] \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "ldmia r2!, {r7} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r6 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "ldr r11, [r0] \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r14} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r3, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "umull r14, r9, r4, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adc r11, r11, r9 \n\t" \ - "stmia r0!, {r10, r11} \n\t" \ - "pop {r3} \n\t" - -#define FAST_MULT_ASM_5_TO_6 \ - "cmp r3, #5 \n\t" \ - "beq 1f \n\t" \ - \ - /* r4 = left high, r5 = right high */ \ - "ldr r4, [r1] \n\t" \ - "ldr r5, [r2] \n\t" \ - \ - "sub r0, #20 \n\t" \ - "sub r1, #20 \n\t" \ - "sub r2, #20 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r4, r8 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r9, r9, r6 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "str r9, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r10, r10, r6 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r9, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "str r10, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r14, r14, r6 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "str r14, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r9, r9, r6 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r14, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "str r9, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r10, r10, r6 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - /* skip past already-loaded (r4, r5) */ \ - "ldr r7, [r1], #8 \n\t" \ - "ldr r8, [r2], #8 \n\t" \ - "mov r9, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "str r10, [r0], #4 \n\t" \ - \ - "umull r11, r12, r4, r5 \n\t" \ - "adds r11, r11, r14 \n\t" \ - "adc r12, r12, r9 \n\t" \ - "stmia r0!, {r11, r12} \n\t" - -#define FAST_MULT_ASM_6 \ - "push {r3} \n\t" \ - "add r0, 12 \n\t" \ - "add r2, 12 \n\t" \ - "ldmia r1!, {r3,r4,r5} \n\t" \ - "ldmia r2!, {r6,r7,r8} \n\t" \ - \ - "umull r11, r12, r3, r6 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r9, r3, r7 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r14, r4, r6 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r3, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r5, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r4, r8 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r5, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "umull r9, r10, r5, r8 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adc r12, r12, r10 \n\t" \ - "stmia r0!, {r11, r12} \n\t" \ - \ - "sub r0, 36 \n\t" \ - "sub r2, 24 \n\t" \ - "ldmia r2!, {r6,r7,r8} \n\t" \ - \ - "umull r11, r12, r3, r6 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r9, r3, r7 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r14, r4, r6 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r3, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r5, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "ldmia r1!, {r3} \n\t" \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r4, r8 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r5, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r3, r6 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "ldmia r1!, {r4} \n\t" \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r5, r8 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r3, r7 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r4, r6 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "ldr r9, [r0] \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, #0 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "ldmia r1!, {r5} \n\t" \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r3, r8 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r4, r7 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r5, r6 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "ldr r10, [r0] \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "ldmia r2!, {r6} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r3, r6 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "ldr r11, [r0] \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r14} \n\t" \ - \ - "ldmia r2!, {r7} \n\t" \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r3, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r5, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "ldr r12, [r0] \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "ldmia r2!, {r8} \n\t" \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r3, r8 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r4, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r5, r6 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r4, r8 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r5, r7 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "umull r10, r11, r5, r8 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adc r14, r14, r11 \n\t" \ - "stmia r0!, {r12, r14} \n\t" \ - "pop {r3} \n\t" - -#define FAST_MULT_ASM_6_TO_7 \ - "cmp r3, #6 \n\t" \ - "beq 1f \n\t" \ - \ - /* r4 = left high, r5 = right high */ \ - "ldr r4, [r1] \n\t" \ - "ldr r5, [r2] \n\t" \ - \ - "sub r0, #24 \n\t" \ - "sub r1, #24 \n\t" \ - "sub r2, #24 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r4, r8 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r9, r9, r6 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "str r9, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r10, r10, r6 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r9, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "str r10, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r14, r14, r6 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "str r14, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r9, r9, r6 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r14, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "str r9, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r10, r10, r6 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r9, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "str r10, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r14, r14, r6 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - /* skip past already-loaded (r4, r5) */ \ - "ldr r7, [r1], #8 \n\t" \ - "ldr r8, [r2], #8 \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "str r14, [r0], #4 \n\t" \ - \ - "umull r11, r12, r4, r5 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adc r12, r12, r10 \n\t" \ - "stmia r0!, {r11, r12} \n\t" - -#define FAST_MULT_ASM_7 \ - "push {r3} \n\t" \ - "add r0, 24 \n\t" \ - "add r2, 24 \n\t" \ - "ldmia r1!, {r3} \n\t" \ - "ldmia r2!, {r6} \n\t" \ - \ - "umull r9, r10, r3, r6 \n\t" \ - "stmia r0!, {r9, r10} \n\t" \ - \ - "sub r0, 20 \n\t" \ - "sub r2, 16 \n\t" \ - "ldmia r2!, {r6, r7, r8} \n\t" \ - "ldmia r1!, {r4, r5} \n\t" \ - \ - "umull r9, r10, r3, r6 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "mov r14, #0 \n\t" \ - "umull r9, r12, r3, r7 \n\t" \ - "adds r10, r10, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r9, r11, r4, r6 \n\t" \ - "adds r10, r10, r9 \n\t" \ - "adcs r12, r12, r11 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r3, r8 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r4, r7 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r5, r6 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "ldmia r1!, {r3} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r6 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "ldr r11, [r0] \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r14} \n\t" \ - \ - "ldmia r2!, {r6} \n\t" \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r4, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r5, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r3, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "ldr r12, [r0] \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r5, r6 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r3, r8 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "umull r9, r10, r3, r6 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adc r12, r12, r10 \n\t" \ - "stmia r0!, {r11, r12} \n\t" \ - \ - "sub r0, 44 \n\t" \ - "sub r1, 16 \n\t" \ - "sub r2, 28 \n\t" \ - "ldmia r1!, {r3,r4,r5} \n\t" \ - "ldmia r2!, {r6,r7,r8} \n\t" \ - \ - "umull r9, r10, r3, r6 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "mov r14, #0 \n\t" \ - "umull r9, r12, r3, r7 \n\t" \ - "adds r10, r10, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r9, r11, r4, r6 \n\t" \ - "adds r10, r10, r9 \n\t" \ - "adcs r12, r12, r11 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r3, r8 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r4, r7 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r5, r6 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "ldmia r1!, {r3} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r6 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "ldr r11, [r0] \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r14} \n\t" \ - \ - "ldmia r1!, {r4} \n\t" \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r5, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r3, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "ldr r12, [r0] \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "ldmia r1!, {r5} \n\t" \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r3, r8 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r4, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r5, r6 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "ldmia r1!, {r3} \n\t" \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r4, r8 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r5, r7 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r3, r6 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "ldr r9, [r0] \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, #0 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "ldmia r2!, {r6} \n\t" \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r4, r6 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r5, r8 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r3, r7 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "ldr r10, [r0] \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "ldmia r2!, {r7} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r4, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r5, r6 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "ldr r11, [r0] \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r14} \n\t" \ - \ - "ldmia r2!, {r8} \n\t" \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r4, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r5, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r3, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "ldr r12, [r0] \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "ldmia r2!, {r6} \n\t" \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r4, r6 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r5, r8 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r3, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r5, r6 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r3, r8 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "umull r10, r11, r3, r6 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adc r14, r14, r11 \n\t" \ - "stmia r0!, {r12, r14} \n\t" \ - "pop {r3} \n\t" - -#define FAST_MULT_ASM_7_TO_8 \ - "cmp r3, #7 \n\t" \ - "beq 1f \n\t" \ - \ - /* r4 = left high, r5 = right high */ \ - "ldr r4, [r1] \n\t" \ - "ldr r5, [r2] \n\t" \ - \ - "sub r0, #28 \n\t" \ - "sub r1, #28 \n\t" \ - "sub r2, #28 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r4, r8 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r9, r9, r6 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "str r9, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r10, r10, r6 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r9, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "str r10, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r14, r14, r6 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "str r14, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r9, r9, r6 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r14, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "str r9, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r10, r10, r6 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r9, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r10, r10, r11 \n\t" \ - "adcs r14, r14, r12 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "str r10, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r14, r14, r6 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "ldr r7, [r1], #4 \n\t" \ - "ldr r8, [r2], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "str r14, [r0], #4 \n\t" \ - \ - "ldr r6, [r0] \n\t" \ - "adds r9, r9, r6 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - /* skip past already-loaded (r4, r5) */ \ - "ldr r7, [r1], #8 \n\t" \ - "ldr r8, [r2], #8 \n\t" \ - "mov r14, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r9, r9, r11 \n\t" \ - "adcs r10, r10, r12 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "str r9, [r0], #4 \n\t" \ - \ - "umull r11, r12, r4, r5 \n\t" \ - "adds r11, r11, r10 \n\t" \ - "adc r12, r12, r14 \n\t" \ - "stmia r0!, {r11, r12} \n\t" - -#define FAST_MULT_ASM_8 \ - "push {r3} \n\t" \ - "add r0, 24 \n\t" \ - "add r2, 24 \n\t" \ - "ldmia r1!, {r3,r4} \n\t" \ - "ldmia r2!, {r6,r7} \n\t" \ - \ - "umull r11, r12, r3, r6 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r9, r3, r7 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r14, r4, r6 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "umull r12, r14, r4, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adc r10, r10, r14 \n\t" \ - "stmia r0!, {r9, r10} \n\t" \ - \ - "sub r0, 28 \n\t" \ - "sub r2, 20 \n\t" \ - "ldmia r2!, {r6,r7,r8} \n\t" \ - "ldmia r1!, {r5} \n\t" \ - \ - "umull r11, r12, r3, r6 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r9, r3, r7 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r14, r4, r6 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r3, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r5, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "ldmia r1!, {r3} \n\t" \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r4, r8 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r5, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r3, r6 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "ldmia r1!, {r4} \n\t" \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r5, r8 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r3, r7 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r4, r6 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "ldr r9, [r0] \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, #0 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "ldmia r2!, {r6} \n\t" \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r5, r6 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r3, r8 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r4, r7 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "ldr r10, [r0] \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "ldmia r2!, {r7} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r6 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "ldr r11, [r0] \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r14} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r3, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "umull r14, r9, r4, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adc r11, r11, r9 \n\t" \ - "stmia r0!, {r10, r11} \n\t" \ - \ - "sub r0, 52 \n\t" \ - "sub r1, 20 \n\t" \ - "sub r2, 32 \n\t" \ - "ldmia r1!, {r3,r4,r5} \n\t" \ - "ldmia r2!, {r6,r7,r8} \n\t" \ - \ - "umull r11, r12, r3, r6 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r9, r3, r7 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r11, r14, r4, r6 \n\t" \ - "adds r12, r12, r11 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r3, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r5, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "ldmia r1!, {r3} \n\t" \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r4, r8 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r5, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r3, r6 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "ldmia r1!, {r4} \n\t" \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r5, r8 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r3, r7 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r4, r6 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "ldr r9, [r0] \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, #0 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "ldmia r1!, {r5} \n\t" \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r3, r8 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r4, r7 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r5, r6 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "ldr r10, [r0] \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "ldmia r1!, {r3} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r4, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r5, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r6 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "ldr r11, [r0] \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r14} \n\t" \ - \ - "ldmia r1!, {r4} \n\t" \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r5, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r3, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "ldr r12, [r0] \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "ldmia r2!, {r6} \n\t" \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r5, r6 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r3, r8 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r4, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "ldmia r2!, {r7} \n\t" \ - "mov r14, #0 \n\t" \ - "umull r9, r10, r5, r7 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r3, r6 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "umull r9, r10, r4, r8 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "ldr r9, [r0] \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adcs r12, r12, #0 \n\t" \ - "adc r14, r14, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "ldmia r2!, {r8} \n\t" \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r5, r8 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r3, r7 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "umull r10, r11, r4, r6 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "ldr r10, [r0] \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r14, r14, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "ldmia r2!, {r6} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r5, r6 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r8 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r4, r7 \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "ldr r11, [r0] \n\t" \ - "adds r14, r14, r11 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r14} \n\t" \ - \ - "ldmia r2!, {r7} \n\t" \ - "mov r11, #0 \n\t" \ - "umull r12, r14, r5, r7 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r3, r6 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "umull r12, r14, r4, r8 \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, r14 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "ldr r12, [r0] \n\t" \ - "adds r9, r9, r12 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r9} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r14, r9, r3, r7 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r14, r9, r4, r6 \n\t" \ - "adds r10, r10, r14 \n\t" \ - "adcs r11, r11, r9 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r10} \n\t" \ - \ - "umull r9, r10, r4, r7 \n\t" \ - "adds r11, r11, r9 \n\t" \ - "adc r12, r12, r10 \n\t" \ - "stmia r0!, {r11, r12} \n\t" \ - "pop {r3} \n\t" - -#define FAST_SQUARE_ASM_5 \ - "push {r2} \n\t" \ - "ldmia r1!, {r2,r3,r4,r5,r6} \n\t" \ - "push {r1} \n\t" \ - \ - "umull r11, r12, r2, r2 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r2, r3 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r8, r11, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r8, r8, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r2, r4 \n\t" \ - "adds r11, r11, r11 \n\t" \ - "adcs r12, r12, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r3 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r2, r5 \n\t" \ - "umull r1, r14, r3, r4 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r11, r11, r14 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r8, r9, r2, r6 \n\t" \ - "umull r1, r14, r3, r5 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adc r10, r10, r10 \n\t" \ - "umull r1, r14, r4, r4 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r3, r6 \n\t" \ - "umull r1, r14, r4, r5 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r11, r11, r14 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r8, #0 \n\t" \ - "umull r1, r10, r4, r6 \n\t" \ - "adds r1, r1, r1 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "adds r11, r11, r1 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "umull r1, r10, r5, r5 \n\t" \ - "adds r11, r11, r1 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r1, r10, r5, r6 \n\t" \ - "adds r1, r1, r1 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "adds r12, r12, r1 \n\t" \ - "adcs r8, r8, r10 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "umull r1, r10, r6, r6 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "stmia r0!, {r8, r11} \n\t" \ - "pop {r1, r2} \n\t" - -#define FAST_SQUARE_ASM_5_TO_6 \ - "cmp r2, #5 \n\t" \ - "beq 1f \n\t" \ - \ - "sub r0, #20 \n\t" \ - "sub r1, #20 \n\t" \ - \ - /* Do off-center multiplication */ \ - "ldmia r1!, {r6,r7,r8,r9,r10,r11} \n\t" \ - "umull r3, r4, r6, r11 \n\t" \ - "umull r6, r5, r7, r11 \n\t" \ - "adds r4, r4, r6 \n\t" \ - "umull r7, r6, r8, r11 \n\t" \ - "adcs r5, r5, r7 \n\t" \ - "umull r8, r7, r9, r11 \n\t" \ - "adcs r6, r6, r8 \n\t" \ - "umull r9, r8, r10, r11 \n\t" \ - "adcs r7, r7, r9 \n\t" \ - "adcs r8, r8, #0 \n\t" \ - \ - /* Multiply by 2 */ \ - "mov r9, #0 \n\t" \ - "adds r3, r3, r3 \n\t" \ - "adcs r4, r4, r4 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - "adcs r6, r6, r6 \n\t" \ - "adcs r7, r7, r7 \n\t" \ - "adcs r8, r8, r8 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - \ - /* Add into previous */ \ - "ldr r14, [r0], #4 \n\t" \ - "adds r3, r3, r14 \n\t" \ - "ldr r14, [r0], #4 \n\t" \ - "adcs r4, r4, r14 \n\t" \ - "ldr r14, [r0], #4 \n\t" \ - "adcs r5, r5, r14 \n\t" \ - "ldr r14, [r0], #4 \n\t" \ - "adcs r6, r6, r14 \n\t" \ - "ldr r14, [r0], #4 \n\t" \ - "adcs r7, r7, r14 \n\t" \ - "adcs r8, r8, #0 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "sub r0, #20 \n\t" \ - \ - /* Perform center multiplication */ \ - "umlal r8, r9, r11, r11 \n\t" \ - "stmia r0!, {r3,r4,r5,r6,r7,r8,r9} \n\t" - -#define FAST_SQUARE_ASM_6 \ - "push {r2} \n\t" \ - "ldmia r1!, {r2,r3,r4,r5,r6,r7} \n\t" \ - "push {r1} \n\t" \ - \ - "umull r11, r12, r2, r2 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r2, r3 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r8, r11, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r8, r8, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r2, r4 \n\t" \ - "adds r11, r11, r11 \n\t" \ - "adcs r12, r12, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r3 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r2, r5 \n\t" \ - "umull r1, r14, r3, r4 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r11, r11, r14 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r8, r9, r2, r6 \n\t" \ - "umull r1, r14, r3, r5 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adc r10, r10, r10 \n\t" \ - "umull r1, r14, r4, r4 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r2, r7 \n\t" \ - "umull r1, r14, r3, r6 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r11, r11, r14 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "umull r1, r14, r4, r5 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r11, r11, r14 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r8, r9, r3, r7 \n\t" \ - "umull r1, r14, r4, r6 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adc r10, r10, r10 \n\t" \ - "umull r1, r14, r5, r5 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r9, r9, r14 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r4, r7 \n\t" \ - "umull r1, r14, r5, r6 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r11, r11, r14 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r8, #0 \n\t" \ - "umull r1, r10, r5, r7 \n\t" \ - "adds r1, r1, r1 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "adds r11, r11, r1 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "umull r1, r10, r6, r6 \n\t" \ - "adds r11, r11, r1 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r1, r10, r6, r7 \n\t" \ - "adds r1, r1, r1 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "adds r12, r12, r1 \n\t" \ - "adcs r8, r8, r10 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "umull r1, r10, r7, r7 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "stmia r0!, {r8, r11} \n\t" \ - "pop {r1, r2} \n\t" - -#define FAST_SQUARE_ASM_6_TO_7 \ - "cmp r2, #6 \n\t" \ - "beq 1f \n\t" \ - \ - "sub r0, #24 \n\t" \ - "sub r1, #24 \n\t" \ - \ - /* Do off-center multiplication */ \ - "ldmia r1!, {r6,r7,r8,r9,r10,r11,r12} \n\t" \ - "umull r3, r4, r6, r12 \n\t" \ - "umull r6, r5, r7, r12 \n\t" \ - "adds r4, r4, r6 \n\t" \ - "umull r7, r6, r8, r12 \n\t" \ - "adcs r5, r5, r7 \n\t" \ - "umull r8, r7, r9, r12 \n\t" \ - "adcs r6, r6, r8 \n\t" \ - "umull r9, r8, r10, r12 \n\t" \ - "adcs r7, r7, r9 \n\t" \ - "umull r10, r9, r11, r12 \n\t" \ - "adcs r8, r8, r10 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - \ - /* Multiply by 2 */ \ - "mov r10, #0 \n\t" \ - "adds r3, r3, r3 \n\t" \ - "adcs r4, r4, r4 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - "adcs r6, r6, r6 \n\t" \ - "adcs r7, r7, r7 \n\t" \ - "adcs r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - \ - /* Add into previous */ \ - "ldr r14, [r0], #4 \n\t" \ - "adds r3, r3, r14 \n\t" \ - "ldr r14, [r0], #4 \n\t" \ - "adcs r4, r4, r14 \n\t" \ - "ldr r14, [r0], #4 \n\t" \ - "adcs r5, r5, r14 \n\t" \ - "ldr r14, [r0], #4 \n\t" \ - "adcs r6, r6, r14 \n\t" \ - "ldr r14, [r0], #4 \n\t" \ - "adcs r7, r7, r14 \n\t" \ - "ldr r14, [r0], #4 \n\t" \ - "adcs r8, r8, r14 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "sub r0, #24 \n\t" \ - \ - /* Perform center multiplication */ \ - "umlal r9, r10, r12, r12 \n\t" \ - "stmia r0!, {r3,r4,r5,r6,r7,r8,r9,r10} \n\t" - -#define FAST_SQUARE_ASM_7 \ - "push {r2} \n\t" \ - "ldmia r1!, {r2, r3, r4, r5, r6, r7, r8} \n\t" \ - "push {r1} \n\t" \ - "sub r1, 4 \n\t" \ - \ - "add r0, 24 \n\t" \ - "umull r9, r10, r2, r8 \n\t" \ - "stmia r0!, {r9, r10} \n\t" \ - "sub r0, 32 \n\t" \ - \ - "umull r11, r12, r2, r2 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r2, r3 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r8, r11, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r8, r8, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r2, r4 \n\t" \ - "adds r11, r11, r11 \n\t" \ - "adcs r12, r12, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r3 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r2, r5 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r3, r4 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r8, r9, r2, r6 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r3, r5 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adc r10, r10, r10 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r4, r4 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r2, r7 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r3, r6 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r4, r5 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "ldmia r1!, {r2} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r8, r9, r3, r7 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r4, r6 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r8, r8, r14 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adc r10, r10, r10 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r5, r5 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r3, r2 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r4, r7 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r5, r6 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r8, r8, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r8, r9, r4, r2 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r5, r7 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adc r10, r10, r10 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r6, r6 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r5, r2 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r6, r7 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r8, #0 \n\t" \ - "umull r1, r10, r6, r2 \n\t" \ - "adds r1, r1, r1 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "adds r11, r11, r1 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "umull r1, r10, r7, r7 \n\t" \ - "adds r11, r11, r1 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r1, r10, r7, r2 \n\t" \ - "adds r1, r1, r1 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "adds r12, r12, r1 \n\t" \ - "adcs r8, r8, r10 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "umull r1, r10, r2, r2 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "stmia r0!, {r8, r11} \n\t" \ - "pop {r1, r2} \n\t" - -#define FAST_SQUARE_ASM_7_TO_8 \ - "cmp r2, #7 \n\t" \ - "beq 1f \n\t" \ - \ - "sub r0, #28 \n\t" \ - "sub r1, #28 \n\t" \ - \ - /* Do off-center multiplication */ \ - "ldmia r1!, {r6,r7,r8,r9,r10,r11,r12,r14} \n\t" \ - "umull r3, r4, r6, r14 \n\t" \ - "umull r6, r5, r7, r14 \n\t" \ - "adds r4, r4, r6 \n\t" \ - "umull r7, r6, r8, r14 \n\t" \ - "adcs r5, r5, r7 \n\t" \ - "umull r8, r7, r9, r14 \n\t" \ - "adcs r6, r6, r8 \n\t" \ - "umull r9, r8, r10, r14 \n\t" \ - "adcs r7, r7, r9 \n\t" \ - "umull r10, r9, r11, r14 \n\t" \ - "adcs r8, r8, r10 \n\t" \ - "umull r11, r10, r12, r14 \n\t" \ - "adcs r9, r9, r11 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - \ - /* Multiply by 2 */ \ - "mov r11, #0 \n\t" \ - "adds r3, r3, r3 \n\t" \ - "adcs r4, r4, r4 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - "adcs r6, r6, r6 \n\t" \ - "adcs r7, r7, r7 \n\t" \ - "adcs r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - \ - /* Add into previous */ \ - "ldr r12, [r0], #4 \n\t" \ - "adds r3, r3, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r4, r4, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r5, r5, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r6, r6, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r7, r7, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r8, r8, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "sub r0, #28 \n\t" \ - \ - /* Perform center multiplication */ \ - "umlal r10, r11, r14, r14 \n\t" \ - "stmia r0!, {r3,r4,r5,r6,r7,r8,r9,r10,r11} \n\t" - -#define FAST_SQUARE_ASM_8 \ - "push {r2} \n\t" \ - "ldmia r1!, {r2,r3,r4,r5,r6,r7,r8,r9} \n\t" \ - "push {r1} \n\t" \ - "sub r1, 8 \n\t" \ - \ - "add r0, 24 \n\t" \ - "umull r10, r11, r2, r8 \n\t" \ - "umull r12, r14, r2, r9 \n\t" \ - "umull r8, r9, r3, r9 \n\t" \ - "adds r11, r11, r12 \n\t" \ - "adcs r12, r14, r8 \n\t" \ - "adcs r14, r9, #0 \n\t" \ - "stmia r0!, {r10, r11, r12, r14} \n\t" \ - "sub r0, 40 \n\t" \ - \ - "umull r11, r12, r2, r2 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r9, #0 \n\t" \ - "umull r10, r11, r2, r3 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r8, r11, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "adds r12, r12, r10 \n\t" \ - "adcs r8, r8, r11 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r11, r12, r2, r4 \n\t" \ - "adds r11, r11, r11 \n\t" \ - "adcs r12, r12, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "umull r11, r12, r3, r3 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r2, r5 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r3, r4 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r8, r9, r2, r6 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r3, r5 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adc r10, r10, r10 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r4, r4 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r2, r7 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r3, r6 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r4, r5 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "ldmia r1!, {r2} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r8, r9, r3, r7 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r4, r6 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r8, r8, r14 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adc r10, r10, r10 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r5, r5 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r3, r2 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r4, r7 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r5, r6 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r8, r8, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "ldmia r1!, {r3} \n\t" \ - "mov r10, #0 \n\t" \ - "umull r8, r9, r4, r2 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r5, r7 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r8, r8, r14 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adc r10, r10, r10 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r6, r6 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r4, r3 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r5, r2 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r6, r7 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "ldr r14, [r0] \n\t" \ - "adds r8, r8, r14 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umull r8, r9, r5, r3 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r6, r2 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adc r10, r10, r10 \n\t" \ - "mov r14, r9 \n\t" \ - "umlal r8, r9, r7, r7 \n\t" \ - "cmp r14, r9 \n\t" \ - "it hi \n\t" \ - "adchi r10, r10, #0 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umull r8, r11, r6, r3 \n\t" \ - "mov r14, r11 \n\t" \ - "umlal r8, r11, r7, r2 \n\t" \ - "cmp r14, r11 \n\t" \ - "it hi \n\t" \ - "adchi r12, r12, #0 \n\t" \ - "adds r8, r8, r8 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adc r12, r12, r12 \n\t" \ - "adds r8, r8, r9 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "adc r12, r12, #0 \n\t" \ - "stmia r0!, {r8} \n\t" \ - \ - "mov r8, #0 \n\t" \ - "umull r1, r10, r7, r3 \n\t" \ - "adds r1, r1, r1 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "adds r11, r11, r1 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "umull r1, r10, r2, r2 \n\t" \ - "adds r11, r11, r1 \n\t" \ - "adcs r12, r12, r10 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "stmia r0!, {r11} \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umull r1, r10, r2, r3 \n\t" \ - "adds r1, r1, r1 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "adds r12, r12, r1 \n\t" \ - "adcs r8, r8, r10 \n\t" \ - "adc r11, r11, #0 \n\t" \ - "stmia r0!, {r12} \n\t" \ - \ - "umull r1, r10, r3, r3 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "adcs r11, r11, r10 \n\t" \ - "stmia r0!, {r8, r11} \n\t" \ - "pop {r1, r2} \n\t" - -#endif /* _UECC_ASM_ARM_MULT_SQUARE_H_ */ diff --git a/lib/micro-ecc/asm_arm_mult_square_umaal.inc b/lib/micro-ecc/asm_arm_mult_square_umaal.inc deleted file mode 100644 index c554d20e385..00000000000 --- a/lib/micro-ecc/asm_arm_mult_square_umaal.inc +++ /dev/null @@ -1,1202 +0,0 @@ -/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ - -#ifndef _UECC_ASM_ARM_MULT_SQUARE_H_ -#define _UECC_ASM_ARM_MULT_SQUARE_H_ - -#define FAST_MULT_ASM_5 \ - "push {r3} \n\t" \ - "ldmia r2!, {r3, r4, r5, r6, r7} \n\t" \ - "push {r2} \n\t" \ - \ - "ldr r2, [r1], #4 \n\t" \ - "umull r8, r9, r3, r2 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umaal r9, r10, r4, r2 \n\t" \ - "mov r11, #0 \n\t" \ - "umaal r10, r11, r5, r2 \n\t" \ - "mov r12, #0 \n\t" \ - "umaal r11, r12, r6, r2 \n\t" \ - "mov r14, #0 \n\t" \ - "umaal r12, r14, r7, r2 \n\t" \ - \ - "ldr r2, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r3, r2 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r4, r2 \n\t" \ - "umaal r10, r11, r5, r2 \n\t" \ - "umaal r11, r12, r6, r2 \n\t" \ - "umaal r12, r14, r7, r2 \n\t" \ - \ - "ldr r2, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r3, r2 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r4, r2 \n\t" \ - "umaal r10, r11, r5, r2 \n\t" \ - "umaal r11, r12, r6, r2 \n\t" \ - "umaal r12, r14, r7, r2 \n\t" \ - \ - "ldr r2, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r3, r2 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r4, r2 \n\t" \ - "umaal r10, r11, r5, r2 \n\t" \ - "umaal r11, r12, r6, r2 \n\t" \ - "umaal r12, r14, r7, r2 \n\t" \ - \ - "ldr r2, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r3, r2 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r4, r2 \n\t" \ - "umaal r10, r11, r5, r2 \n\t" \ - "umaal r11, r12, r6, r2 \n\t" \ - "umaal r12, r14, r7, r2 \n\t" \ - \ - "str r9, [r0], #4 \n\t" \ - "str r10, [r0], #4 \n\t" \ - "str r11, [r0], #4 \n\t" \ - "str r12, [r0], #4 \n\t" \ - "str r14, [r0], #4 \n\t" \ - \ - "pop {r2, r3} \n\t" - -#define FAST_MULT_ASM_5_TO_6 \ - "cmp r3, #5 \n\t" \ - "beq 1f \n\t" \ - \ - /* r4 = left high */ \ - "ldr r4, [r1] \n\t" \ - \ - "sub r0, #20 \n\t" \ - "sub r1, #20 \n\t" \ - "sub r2, #20 \n\t" \ - \ - /* Do right side */ \ - "ldr r14, [r2], #4 \n\t" \ - "mov r5, #0 \n\t" \ - "ldr r6, [r0], #4 \n\t" \ - "umaal r5, r6, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r7, [r0], #4 \n\t" \ - "umaal r6, r7, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r8, [r0], #4 \n\t" \ - "umaal r7, r8, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r9, [r0], #4 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r10, [r0], #4 \n\t" \ - "umaal r9, r10, r4, r14 \n\t" \ - "sub r0, #20 \n\t" \ - \ - /* r4 = right high */ \ - "ldr r4, [r2], #4 \n\t" \ - \ - /* Do left side */ \ - "ldr r14, [r1], #4 \n\t" \ - "mov r12, #0 \n\t" \ - "umaal r12, r5, r4, r14 \n\t" \ - "str r12, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r5, r6, r4, r14 \n\t" \ - "str r5, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r6, r7, r4, r14 \n\t" \ - "str r6, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r7, r8, r4, r14 \n\t" \ - "str r7, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r9, r10, r4, r14 \n\t" \ - "stmia r0!, {r9, r10} \n\t" - -#define FAST_MULT_ASM_6 \ - "ldmia r2!, {r4, r5, r6} \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "umull r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "mov r11, #0 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "str r9, [r0], #4 \n\t" \ - "str r10, [r0], #4 \n\t" \ - "str r11, [r0], #4 \n\t" \ - \ - "sub r0, #24 \n\t" \ - "sub r1, #24 \n\t" \ - "ldmia r2!, {r4, r5, r6} \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "mov r9, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "mov r11, #0 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "str r9, [r0], #4 \n\t" \ - "str r10, [r0], #4 \n\t" \ - "str r11, [r0], #4 \n\t" - -#define FAST_MULT_ASM_6_TO_7 \ - "cmp r3, #6 \n\t" \ - "beq 1f \n\t" \ - \ - /* r4 = left high */ \ - "ldr r4, [r1] \n\t" \ - \ - "sub r0, #24 \n\t" \ - "sub r1, #24 \n\t" \ - "sub r2, #24 \n\t" \ - \ - /* Do right side */ \ - "ldr r14, [r2], #4 \n\t" \ - "mov r5, #0 \n\t" \ - "ldr r6, [r0], #4 \n\t" \ - "umaal r5, r6, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r7, [r0], #4 \n\t" \ - "umaal r6, r7, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r8, [r0], #4 \n\t" \ - "umaal r7, r8, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r9, [r0], #4 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r10, [r0], #4 \n\t" \ - "umaal r9, r10, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r11, [r0], #4 \n\t" \ - "umaal r10, r11, r4, r14 \n\t" \ - "sub r0, #24 \n\t" \ - \ - /* r4 = right high */ \ - "ldr r4, [r2], #4 \n\t" \ - \ - /* Do left side */ \ - "ldr r14, [r1], #4 \n\t" \ - "mov r12, #0 \n\t" \ - "umaal r12, r5, r4, r14 \n\t" \ - "str r12, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r5, r6, r4, r14 \n\t" \ - "str r5, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r6, r7, r4, r14 \n\t" \ - "str r6, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r7, r8, r4, r14 \n\t" \ - "str r7, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r9, r10, r4, r14 \n\t" \ - "str r9, [r0], #4 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r10, r11, r4, r14 \n\t" \ - "stmia r0!, {r10, r11} \n\t" - -#define FAST_MULT_ASM_7 \ - "ldmia r2!, {r4, r5, r6, r7} \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "umull r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "mov r11, #0 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "mov r12, #0 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "str r9, [r0], #4 \n\t" \ - "str r10, [r0], #4 \n\t" \ - "str r11, [r0], #4 \n\t" \ - "str r12, [r0], #4 \n\t" \ - \ - "sub r0, #28 \n\t" \ - "sub r1, #28 \n\t" \ - "ldmia r2!, {r4, r5, r6} \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "mov r9, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "mov r11, #0 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - \ - "str r9, [r0], #4 \n\t" \ - "str r10, [r0], #4 \n\t" \ - "str r11, [r0], #4 \n\t" - -#define FAST_MULT_ASM_7_TO_8 \ - "cmp r3, #7 \n\t" \ - "beq 1f \n\t" \ - "push {r3} \n\t" \ - \ - /* r4 = left high */ \ - "ldr r4, [r1] \n\t" \ - \ - "sub r0, #28 \n\t" \ - "sub r1, #28 \n\t" \ - "sub r2, #28 \n\t" \ - \ - /* Do right side */ \ - "ldr r14, [r2], #4 \n\t" \ - "mov r5, #0 \n\t" \ - "ldr r6, [r0], #4 \n\t" \ - "umaal r5, r6, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r7, [r0], #4 \n\t" \ - "umaal r6, r7, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r8, [r0], #4 \n\t" \ - "umaal r7, r8, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r9, [r0], #4 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r10, [r0], #4 \n\t" \ - "umaal r9, r10, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r11, [r0], #4 \n\t" \ - "umaal r10, r11, r4, r14 \n\t" \ - "ldr r14, [r2], #4 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "umaal r11, r12, r4, r14 \n\t" \ - "sub r0, #28 \n\t" \ - \ - /* r4 = right high */ \ - "ldr r4, [r2], #4 \n\t" \ - \ - /* Do left side */ \ - "ldr r14, [r1], #4 \n\t" \ - "mov r3, #0 \n\t" \ - "umaal r3, r5, r4, r14 \n\t" \ - "str r3, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r5, r6, r4, r14 \n\t" \ - "str r5, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r6, r7, r4, r14 \n\t" \ - "str r6, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r7, r8, r4, r14 \n\t" \ - "str r7, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r9, r10, r4, r14 \n\t" \ - "str r9, [r0], #4 \n\t" \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r10, r11, r4, r14 \n\t" \ - "str r10, [r0], #4 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "umaal r11, r12, r4, r14 \n\t" \ - "stmia r0!, {r11, r12} \n\t" \ - "pop {r3} \n\t" - -#define FAST_MULT_ASM_8 \ - "ldmia r2!, {r4, r5, r6, r7} \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "umull r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "mov r11, #0 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "mov r12, #0 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "str r9, [r0], #4 \n\t" \ - "str r10, [r0], #4 \n\t" \ - "str r11, [r0], #4 \n\t" \ - "str r12, [r0], #4 \n\t" \ - \ - "sub r0, #32 \n\t" \ - "sub r1, #32 \n\t" \ - "ldmia r2!, {r4, r5, r6, r7} \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "mov r9, #0 \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "mov r10, #0 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "mov r11, #0 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "mov r12, #0 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "ldr r14, [r1], #4 \n\t" \ - "ldr r8, [r0] \n\t" \ - "umaal r8, r9, r4, r14 \n\t" \ - "str r8, [r0], #4 \n\t" \ - "umaal r9, r10, r5, r14 \n\t" \ - "umaal r10, r11, r6, r14 \n\t" \ - "umaal r11, r12, r7, r14 \n\t" \ - \ - "str r9, [r0], #4 \n\t" \ - "str r10, [r0], #4 \n\t" \ - "str r11, [r0], #4 \n\t" \ - "str r12, [r0], #4 \n\t" - -#define FAST_SQUARE_ASM_5 \ - "ldmia r1!, {r9,r10,r11,r12,r14} \n\t" \ - "push {r1, r2} \n\t" \ - \ - "umull r1, r2, r10, r9 \n\t" \ - "mov r3, #0 \n\t" \ - "umaal r2, r3, r11, r9 \n\t" \ - "mov r4, #0 \n\t" \ - "umaal r3, r4, r12, r9 \n\t" \ - "mov r5, #0 \n\t" \ - "umaal r4, r5, r14, r9 \n\t" \ - \ - "mov r6, #0 \n\t" \ - "umaal r6, r3, r11, r10 \n\t" \ - "umaal r3, r4, r12, r10 \n\t" \ - "adds r1, r1, r1 \n\t" \ - "adcs r2, r2, r2 \n\t" \ - "adcs r6, r6, r6 \n\t" \ - "adcs r3, r3, r3 \n\t" \ - \ - "umull r7, r8, r9, r9 \n\t" \ - /* Store carry in r9 */ \ - "mov r9, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - "adds r8, r8, r1 \n\t" \ - "stmia r0!, {r7,r8} \n\t" \ - \ - "umull r7, r8, r10, r10 \n\t" \ - "adcs r7, r7, r2 \n\t" \ - "adcs r8, r8, r6 \n\t" \ - "stmia r0!, {r7,r8} \n\t" \ - \ - "umaal r4, r5, r14, r10 \n\t" \ - /* Store carry in r10 */ \ - "mov r10, #0 \n\t" \ - "adc r10, r10, #0 \n\t" \ - \ - "mov r1, #0 \n\t" \ - "umaal r1, r4, r12, r11 \n\t" \ - "umaal r4, r5, r14, r11 \n\t" \ - \ - "mov r2, #0 \n\t" \ - "umaal r2, r5, r14, r12 \n\t" \ - /* Load carry from r9 */ \ - "lsrs r9, #1 \n\t" \ - "adcs r1, r1, r1 \n\t" \ - "adcs r4, r4, r4 \n\t" \ - "adcs r2, r2, r2 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - /* r9 is 0 now */ \ - "adc r9, r9, #0 \n\t" \ - \ - /* Use carry from r10 */ \ - "umaal r3, r10, r11, r11 \n\t" \ - "adds r10, r10, r1 \n\t" \ - "stmia r0!, {r3,r10} \n\t" \ - \ - "umull r6, r10, r12, r12 \n\t" \ - "adcs r6, r6, r4 \n\t" \ - "adcs r10, r10, r2 \n\t" \ - "stmia r0!, {r6,r10} \n\t" \ - \ - "umull r6, r10, r14, r14 \n\t" \ - "adcs r6, r6, r5 \n\t" \ - "adcs r10, r10, r9 \n\t" \ - "stmia r0!, {r6,r10} \n\t" \ - "pop {r1, r2} \n\t" - -#define FAST_SQUARE_ASM_5_TO_6 \ - "cmp r2, #5 \n\t" \ - "beq 1f \n\t" \ - \ - "sub r0, #20 \n\t" \ - "sub r1, #20 \n\t" \ - \ - /* Do off-center multiplication */ \ - "ldmia r1!, {r5,r6,r7,r8,r9,r14} \n\t" \ - "umull r3, r4, r5, r14 \n\t" \ - "mov r5, #0 \n\t" \ - "umaal r4, r5, r6, r14 \n\t" \ - "mov r6, #0 \n\t" \ - "umaal r5, r6, r7, r14 \n\t" \ - "mov r7, #0 \n\t" \ - "umaal r6, r7, r8, r14 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r7, r8, r9, r14 \n\t" \ - \ - /* Multiply by 2 */ \ - "mov r9, #0 \n\t" \ - "adds r3, r3, r3 \n\t" \ - "adcs r4, r4, r4 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - "adcs r6, r6, r6 \n\t" \ - "adcs r7, r7, r7 \n\t" \ - "adcs r8, r8, r8 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - \ - /* Add into previous */ \ - "ldr r12, [r0], #4 \n\t" \ - "adds r3, r3, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r4, r4, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r5, r5, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r6, r6, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r7, r7, r12 \n\t" \ - "adcs r8, r8, #0 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "sub r0, #20 \n\t" \ - \ - /* Perform center multiplication */ \ - "umlal r8, r9, r14, r14 \n\t" \ - "stmia r0!, {r3,r4,r5,r6,r7,r8,r9} \n\t" - -#define FAST_SQUARE_ASM_6 \ - "ldmia r1!, {r8,r9,r10,r11,r12,r14} \n\t" \ - "push {r1, r2} \n\t" \ - \ - "umull r1, r2, r9, r8 \n\t" \ - "mov r3, #0 \n\t" \ - "umaal r2, r3, r10, r8 \n\t" \ - "mov r4, #0 \n\t" \ - "umaal r3, r4, r11, r8 \n\t" \ - "mov r5, #0 \n\t" \ - "umaal r4, r5, r12, r8 \n\t" \ - "mov r6, #0 \n\t" \ - "umaal r5, r6, r14, r8 \n\t" \ - \ - "mov r7, #0 \n\t" \ - "umaal r7, r3, r10, r9 \n\t" \ - "umaal r3, r4, r11, r9 \n\t" \ - "umaal r4, r5, r12, r9 \n\t" \ - "push {r4, r5} \n\t" \ - "adds r1, r1, r1 \n\t" \ - "adcs r2, r2, r2 \n\t" \ - "adcs r7, r7, r7 \n\t" \ - "adcs r3, r3, r3 \n\t" \ - \ - "umull r4, r5, r8, r8 \n\t" \ - /* Store carry in r8 */ \ - "mov r8, #0 \n\t" \ - "adc r8, r8, #0 \n\t" \ - "adds r5, r5, r1 \n\t" \ - "stmia r0!, {r4,r5} \n\t" \ - \ - "umull r4, r5, r9, r9 \n\t" \ - "adcs r4, r4, r2 \n\t" \ - "adcs r5, r5, r7 \n\t" \ - "stmia r0!, {r4,r5} \n\t" \ - \ - "pop {r4, r5} \n\t" \ - "umaal r5, r6, r14, r9 \n\t" \ - /* Store carry in r9 */ \ - "mov r9, #0 \n\t" \ - "adc r9, r9, #0 \n\t" \ - \ - "mov r1, #0 \n\t" \ - "umaal r1, r4, r11, r10 \n\t" \ - "umaal r4, r5, r12, r10 \n\t" \ - "umaal r5, r6, r14, r10 \n\t" \ - \ - "mov r2, #0 \n\t" \ - "umaal r2, r5, r12, r11 \n\t" \ - "umaal r5, r6, r14, r11 \n\t" \ - \ - "mov r7, #0 \n\t" \ - "umaal r7, r6, r14, r12 \n\t" \ - \ - /* Load carry from r8 */ \ - "lsrs r8, #1 \n\t" \ - "adcs r1, r1, r1 \n\t" \ - "adcs r4, r4, r4 \n\t" \ - "adcs r2, r2, r2 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - "adcs r7, r7, r7 \n\t" \ - "adcs r6, r6, r6 \n\t" \ - "adc r8, r8, #0 \n\t" \ - \ - /* Use carry from r9 */ \ - "umaal r3, r9, r10, r10 \n\t" \ - "adds r9, r9, r1 \n\t" \ - "stmia r0!, {r3,r9} \n\t" \ - \ - "umull r9, r10, r11, r11 \n\t" \ - "adcs r9, r9, r4 \n\t" \ - "adcs r10, r10, r2 \n\t" \ - "stmia r0!, {r9,r10} \n\t" \ - \ - "umull r9, r10, r12, r12 \n\t" \ - "adcs r9, r9, r5 \n\t" \ - "adcs r10, r10, r7 \n\t" \ - "stmia r0!, {r9,r10} \n\t" \ - \ - "umull r9, r10, r14, r14 \n\t" \ - "adcs r9, r9, r6 \n\t" \ - "adcs r10, r10, r8 \n\t" \ - "stmia r0!, {r9,r10} \n\t" \ - "pop {r1, r2} \n\t" - -#define FAST_SQUARE_ASM_6_TO_7 \ - "cmp r2, #6 \n\t" \ - "beq 1f \n\t" \ - \ - "sub r0, #24 \n\t" \ - "sub r1, #24 \n\t" \ - \ - /* Do off-center multiplication */ \ - "ldmia r1!, {r5,r6,r7,r8,r9,r10,r14} \n\t" \ - "umull r3, r4, r5, r14 \n\t" \ - "mov r5, #0 \n\t" \ - "umaal r4, r5, r6, r14 \n\t" \ - "mov r6, #0 \n\t" \ - "umaal r5, r6, r7, r14 \n\t" \ - "mov r7, #0 \n\t" \ - "umaal r6, r7, r8, r14 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r7, r8, r9, r14 \n\t" \ - "mov r9, #0 \n\t" \ - "umaal r8, r9, r10, r14 \n\t" \ - \ - /* Multiply by 2 */ \ - "mov r10, #0 \n\t" \ - "adds r3, r3, r3 \n\t" \ - "adcs r4, r4, r4 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - "adcs r6, r6, r6 \n\t" \ - "adcs r7, r7, r7 \n\t" \ - "adcs r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - \ - /* Add into previous */ \ - "ldr r12, [r0], #4 \n\t" \ - "adds r3, r3, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r4, r4, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r5, r5, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r6, r6, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r7, r7, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r8, r8, r12 \n\t" \ - "adcs r9, r9, #0 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "sub r0, #24 \n\t" \ - \ - /* Perform center multiplication */ \ - "umlal r9, r10, r14, r14 \n\t" \ - "stmia r0!, {r3,r4,r5,r6,r7,r8,r9,r10} \n\t" - -#define FAST_SQUARE_ASM_7 \ - "ldmia r1!, {r9,r10,r11,r12} \n\t" \ - "push {r2} \n\t" \ - \ - "umull r14, r2, r10, r9 \n\t" \ - "mov r3, #0 \n\t" \ - "umaal r2, r3, r11, r9 \n\t" \ - "mov r4, #0 \n\t" \ - "umaal r3, r4, r12, r9 \n\t" \ - \ - "mov r5, #0 \n\t" \ - "umaal r5, r3, r11, r10 \n\t" \ - "adds r14, r14, r14 \n\t" \ - "adcs r2, r2, r2 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - /* Store carry in r7 */ \ - "mov r7, #0 \n\t" \ - "adc r7, r7, #0 \n\t" \ - \ - "umull r6, r8, r9, r9 \n\t" \ - "adds r8, r8, r14 \n\t" \ - "stmia r0!, {r6,r8} \n\t" \ - \ - "umull r6, r8, r10, r10 \n\t" \ - "adcs r6, r6, r2 \n\t" \ - "adcs r8, r8, r5 \n\t" \ - "stmia r0!, {r6,r8} \n\t" \ - /* Store carry in r8 */ \ - "mov r8, #0 \n\t" \ - "adc r8, r8, #0 \n\t" \ - \ - "ldmia r1!, {r2, r6, r14} \n\t" \ - "push {r1} \n\t" \ - "umaal r3, r4, r2, r9 \n\t" \ - "mov r5, #0 \n\t" \ - "umaal r4, r5, r6, r9 \n\t" \ - "mov r1, #0 \n\t" \ - "umaal r5, r1, r14, r9 \n\t" \ - \ - "mov r9, #0 \n\t" \ - "umaal r3, r9, r12, r10 \n\t" \ - "umaal r9, r4, r2, r10 \n\t" \ - "umaal r4, r5, r6, r10 \n\t" \ - "umaal r5, r1, r14, r10 \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umaal r10, r9, r12, r11 \n\t" \ - "umaal r9, r4, r2, r11 \n\t" \ - "umaal r4, r5, r6, r11 \n\t" \ - "umaal r5, r1, r14, r11 \n\t" \ - \ - /* Load carry from r7 */ \ - "lsrs r7, #1 \n\t" \ - "adcs r3, r3, r3 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - /* Store carry back in r7 */ \ - "adc r7, r7, #0 \n\t" \ - \ - /* Use carry from r8 */ \ - "umaal r3, r8, r11, r11 \n\t" \ - "adds r8, r8, r10 \n\t" \ - "stmia r0!, {r3,r8} \n\t" \ - /* Store carry back in r8 */ \ - "mov r8, #0 \n\t" \ - "adc r8, r8, #0 \n\t" \ - \ - "mov r3, #0 \n\t" \ - "umaal r3, r4, r2, r12 \n\t" \ - "umaal r4, r5, r6, r12 \n\t" \ - "umaal r5, r1, r14, r12 \n\t" \ - \ - "mov r10, #0 \n\t" \ - "umaal r10, r5, r6, r2 \n\t" \ - "umaal r5, r1, r14, r2 \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umaal r11, r1, r14, r6 \n\t" \ - \ - /* Load carry from r7 */ \ - "lsrs r7, #1 \n\t" \ - "adcs r3, r3, r3 \n\t" \ - "adcs r4, r4, r4 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adcs r1, r1, r1 \n\t" \ - "adc r7, r7, #0 \n\t" \ - \ - /* Use carry from r8 */ \ - "umaal r8, r9, r12, r12 \n\t" \ - "adds r9, r9, r3 \n\t" \ - "stmia r0!, {r8,r9} \n\t" \ - \ - "umull r8, r9, r2, r2 \n\t" \ - "adcs r8, r8, r4 \n\t" \ - "adcs r9, r9, r10 \n\t" \ - "stmia r0!, {r8,r9} \n\t" \ - \ - "umull r8, r9, r6, r6 \n\t" \ - "adcs r8, r8, r5 \n\t" \ - "adcs r9, r9, r11 \n\t" \ - "stmia r0!, {r8,r9} \n\t" \ - \ - "umull r8, r9, r14, r14 \n\t" \ - "adcs r8, r8, r1 \n\t" \ - "adcs r9, r9, r7 \n\t" \ - "stmia r0!, {r8,r9} \n\t" \ - "pop {r1, r2} \n\t" - -#define FAST_SQUARE_ASM_7_TO_8 \ - "cmp r2, #7 \n\t" \ - "beq 1f \n\t" \ - \ - "sub r0, #28 \n\t" \ - "sub r1, #28 \n\t" \ - \ - /* Do off-center multiplication */ \ - "ldmia r1!, {r5,r6,r7,r8,r9,r10,r11,r14} \n\t" \ - "umull r3, r4, r5, r14 \n\t" \ - "mov r5, #0 \n\t" \ - "umaal r4, r5, r6, r14 \n\t" \ - "mov r6, #0 \n\t" \ - "umaal r5, r6, r7, r14 \n\t" \ - "mov r7, #0 \n\t" \ - "umaal r6, r7, r8, r14 \n\t" \ - "mov r8, #0 \n\t" \ - "umaal r7, r8, r9, r14 \n\t" \ - "mov r9, #0 \n\t" \ - "umaal r8, r9, r10, r14 \n\t" \ - "mov r10, #0 \n\t" \ - "umaal r9, r10, r11, r14 \n\t" \ - \ - /* Multiply by 2 */ \ - "mov r11, #0 \n\t" \ - "adds r3, r3, r3 \n\t" \ - "adcs r4, r4, r4 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - "adcs r6, r6, r6 \n\t" \ - "adcs r7, r7, r7 \n\t" \ - "adcs r8, r8, r8 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adcs r10, r10, r10 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - \ - /* Add into previous */ \ - "ldr r12, [r0], #4 \n\t" \ - "adds r3, r3, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r4, r4, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r5, r5, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r6, r6, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r7, r7, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r8, r8, r12 \n\t" \ - "ldr r12, [r0], #4 \n\t" \ - "adcs r9, r9, r12 \n\t" \ - "adcs r10, r10, #0 \n\t" \ - "adcs r11, r11, #0 \n\t" \ - "sub r0, #28 \n\t" \ - \ - /* Perform center multiplication */ \ - "umlal r10, r11, r14, r14 \n\t" \ - "stmia r0!, {r3,r4,r5,r6,r7,r8,r9,r10,r11} \n\t" - -#define FAST_SQUARE_ASM_8 \ - "ldmia r1!, {r10,r11,r12,r14} \n\t" \ - "push {r2} \n\t" \ - \ - "umull r2, r3, r11, r10 \n\t" \ - "mov r4, #0 \n\t" \ - "umaal r3, r4, r12, r10 \n\t" \ - "mov r5, #0 \n\t" \ - "umaal r4, r5, r14, r10 \n\t" \ - \ - "mov r6, #0 \n\t" \ - "umaal r6, r4, r12, r11 \n\t" \ - "adds r2, r2, r2 \n\t" \ - "adcs r3, r3, r3 \n\t" \ - "adcs r6, r6, r6 \n\t" \ - /* Store carry in r7 */ \ - "mov r7, #0 \n\t" \ - "adc r7, r7, #0 \n\t" \ - \ - "umull r8, r9, r10, r10 \n\t" \ - "adds r9, r9, r2 \n\t" \ - "stmia r0!, {r8,r9} \n\t" \ - \ - "umull r8, r9, r11, r11 \n\t" \ - "adcs r8, r8, r3 \n\t" \ - "adcs r9, r9, r6 \n\t" \ - "stmia r0!, {r8,r9} \n\t" \ - /* Store carry in r8 */ \ - "mov r8, #0 \n\t" \ - "adc r8, r8, #0 \n\t" \ - \ - "ldmia r1!, {r2, r3} \n\t" \ - "push {r1} \n\t" \ - "umaal r4, r5, r2, r10 \n\t" \ - "mov r6, #0 \n\t" \ - "umaal r5, r6, r3, r10 \n\t" \ - \ - "mov r9, #0 \n\t" \ - "umaal r9, r4, r14, r11 \n\t" \ - "umaal r4, r5, r2, r11 \n\t" \ - \ - "mov r1, #0 \n\t" \ - "umaal r1, r4, r14, r12 \n\t" \ - \ - /* Load carry from r7 */ \ - "lsrs r7, #1 \n\t" \ - "adcs r9, r9, r9 \n\t" \ - "adcs r1, r1, r1 \n\t" \ - /* Store carry back in r7 */ \ - "adc r7, r7, #0 \n\t" \ - \ - /* Use carry from r8 */ \ - "umaal r8, r9, r12, r12 \n\t" \ - "adds r9, r9, r1 \n\t" \ - "stmia r0!, {r8,r9} \n\t" \ - /* Store carry back in r8 */ \ - "mov r8, #0 \n\t" \ - "adc r8, r8, #0 \n\t" \ - \ - "pop {r1} \n\t" \ - /* TODO could fix up r1 value on stack here */ \ - /* and leave the value on the stack (rather */ \ - /* than popping) if supporting curves > 256 bits */ \ - "ldr r9, [r1], #4 \n\t" \ - "ldr r1, [r1] \n\t" \ - \ - "push {r7} \n\t" \ - "umaal r5, r6, r9, r10 \n\t" \ - "mov r7, #0 \n\t" \ - "umaal r6, r7, r1, r10 \n\t" \ - /* Carry now stored in r10 */ \ - "pop {r10} \n\t" \ - \ - "umaal r4, r5, r3, r11 \n\t" \ - "umaal r5, r6, r9, r11 \n\t" \ - "umaal r6, r7, r1, r11 \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umaal r11, r4, r2, r12 \n\t" \ - "umaal r4, r5, r3, r12 \n\t" \ - "umaal r5, r6, r9, r12 \n\t" \ - "umaal r6, r7, r1, r12 \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umaal r12, r4, r2, r14 \n\t" \ - "umaal r4, r5, r3, r14 \n\t" \ - "umaal r5, r6, r9, r14 \n\t" \ - "umaal r6, r7, r1, r14 \n\t" \ - \ - /* Load carry from r10 */ \ - "lsrs r10, #1 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adcs r12, r12, r12 \n\t" \ - "adc r10, r10, #0 \n\t" \ - \ - /* Use carry from r8 */ \ - "umaal r8, r11, r14, r14 \n\t" \ - "adds r11, r11, r12 \n\t" \ - "stmia r0!, {r8,r11} \n\t" \ - /* Store carry back in r8 */ \ - "mov r8, #0 \n\t" \ - "adc r8, r8, #0 \n\t" \ - \ - "mov r11, #0 \n\t" \ - "umaal r11, r5, r3, r2 \n\t" \ - "umaal r5, r6, r9, r2 \n\t" \ - "umaal r6, r7, r1, r2 \n\t" \ - \ - "mov r12, #0 \n\t" \ - "umaal r12, r6, r9, r3 \n\t" \ - "umaal r6, r7, r1, r3 \n\t" \ - \ - "mov r14, #0 \n\t" \ - "umaal r14, r7, r1, r9 \n\t" \ - \ - /* Load carry from r10 */ \ - "lsrs r10, #1 \n\t" \ - "adcs r4, r4, r4 \n\t" \ - "adcs r11, r11, r11 \n\t" \ - "adcs r5, r5, r5 \n\t" \ - "adcs r12, r12, r12 \n\t" \ - "adcs r6, r6, r6 \n\t" \ - "adcs r14, r14, r14 \n\t" \ - "adcs r7, r7, r7 \n\t" \ - "adc r10, r10, #0 \n\t" \ - \ - /* Use carry from r8 */ \ - "umaal r4, r8, r2, r2 \n\t" \ - "adds r8, r8, r11 \n\t" \ - "stmia r0!, {r4,r8} \n\t" \ - \ - "umull r4, r8, r3, r3 \n\t" \ - "adcs r4, r4, r5 \n\t" \ - "adcs r8, r8, r12 \n\t" \ - "stmia r0!, {r4,r8} \n\t" \ - \ - "umull r4, r8, r9, r9 \n\t" \ - "adcs r4, r4, r6 \n\t" \ - "adcs r8, r8, r14 \n\t" \ - "stmia r0!, {r4,r8} \n\t" \ - \ - "umull r4, r8, r1, r1 \n\t" \ - "adcs r4, r4, r7 \n\t" \ - "adcs r8, r8, r10 \n\t" \ - "stmia r0!, {r4,r8} \n\t" \ - /* TODO pop {r1, r2} if supporting curves > 256 bits */ \ - "pop {r2} \n\t" - -#endif /* _UECC_ASM_ARM_MULT_SQUARE_H_ */ diff --git a/lib/micro-ecc/curve-specific.inc b/lib/micro-ecc/curve-specific.inc deleted file mode 100644 index f5d3da842c8..00000000000 --- a/lib/micro-ecc/curve-specific.inc +++ /dev/null @@ -1,1249 +0,0 @@ -/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ - -#ifndef _UECC_CURVE_SPECIFIC_H_ -#define _UECC_CURVE_SPECIFIC_H_ - -#define num_bytes_secp160r1 20 -#define num_bytes_secp192r1 24 -#define num_bytes_secp224r1 28 -#define num_bytes_secp256r1 32 -#define num_bytes_secp256k1 32 - -#if (uECC_WORD_SIZE == 1) - -#define num_words_secp160r1 20 -#define num_words_secp192r1 24 -#define num_words_secp224r1 28 -#define num_words_secp256r1 32 -#define num_words_secp256k1 32 - -#define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) \ - 0x##a, 0x##b, 0x##c, 0x##d, 0x##e, 0x##f, 0x##g, 0x##h -#define BYTES_TO_WORDS_4(a, b, c, d) 0x##a, 0x##b, 0x##c, 0x##d - -#elif (uECC_WORD_SIZE == 4) - -#define num_words_secp160r1 5 -#define num_words_secp192r1 6 -#define num_words_secp224r1 7 -#define num_words_secp256r1 8 -#define num_words_secp256k1 8 - -#define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) 0x##d##c##b##a, 0x##h##g##f##e -#define BYTES_TO_WORDS_4(a, b, c, d) 0x##d##c##b##a - -#elif (uECC_WORD_SIZE == 8) - -#define num_words_secp160r1 3 -#define num_words_secp192r1 3 -#define num_words_secp224r1 4 -#define num_words_secp256r1 4 -#define num_words_secp256k1 4 - -#define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) 0x##h##g##f##e##d##c##b##a##ull -#define BYTES_TO_WORDS_4(a, b, c, d) 0x##d##c##b##a##ull - -#endif /* uECC_WORD_SIZE */ - -#if uECC_SUPPORTS_secp160r1 || uECC_SUPPORTS_secp192r1 || \ - uECC_SUPPORTS_secp224r1 || uECC_SUPPORTS_secp256r1 -static void double_jacobian_default(uECC_word_t * X1, - uECC_word_t * Y1, - uECC_word_t * Z1, - uECC_Curve curve) { - /* t1 = X, t2 = Y, t3 = Z */ - uECC_word_t t4[uECC_MAX_WORDS]; - uECC_word_t t5[uECC_MAX_WORDS]; - wordcount_t num_words = curve->num_words; - - if (uECC_vli_isZero(Z1, num_words)) { - return; - } - - uECC_vli_modSquare_fast(t4, Y1, curve); /* t4 = y1^2 */ - uECC_vli_modMult_fast(t5, X1, t4, curve); /* t5 = x1*y1^2 = A */ - uECC_vli_modSquare_fast(t4, t4, curve); /* t4 = y1^4 */ - uECC_vli_modMult_fast(Y1, Y1, Z1, curve); /* t2 = y1*z1 = z3 */ - uECC_vli_modSquare_fast(Z1, Z1, curve); /* t3 = z1^2 */ - - uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = x1 + z1^2 */ - uECC_vli_modAdd(Z1, Z1, Z1, curve->p, num_words); /* t3 = 2*z1^2 */ - uECC_vli_modSub(Z1, X1, Z1, curve->p, num_words); /* t3 = x1 - z1^2 */ - uECC_vli_modMult_fast(X1, X1, Z1, curve); /* t1 = x1^2 - z1^4 */ - - uECC_vli_modAdd(Z1, X1, X1, curve->p, num_words); /* t3 = 2*(x1^2 - z1^4) */ - uECC_vli_modAdd(X1, X1, Z1, curve->p, num_words); /* t1 = 3*(x1^2 - z1^4) */ - if (uECC_vli_testBit(X1, 0)) { - uECC_word_t l_carry = uECC_vli_add(X1, X1, curve->p, num_words); - uECC_vli_rshift1(X1, num_words); - X1[num_words - 1] |= l_carry << (uECC_WORD_BITS - 1); - } else { - uECC_vli_rshift1(X1, num_words); - } - /* t1 = 3/2*(x1^2 - z1^4) = B */ - - uECC_vli_modSquare_fast(Z1, X1, curve); /* t3 = B^2 */ - uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - A */ - uECC_vli_modSub(Z1, Z1, t5, curve->p, num_words); /* t3 = B^2 - 2A = x3 */ - uECC_vli_modSub(t5, t5, Z1, curve->p, num_words); /* t5 = A - x3 */ - uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = B * (A - x3) */ - uECC_vli_modSub(t4, X1, t4, curve->p, num_words); /* t4 = B * (A - x3) - y1^4 = y3 */ - - uECC_vli_set(X1, Z1, num_words); - uECC_vli_set(Z1, Y1, num_words); - uECC_vli_set(Y1, t4, num_words); -} - -/* Computes result = x^3 + ax + b. result must not overlap x. */ -static void x_side_default(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve) { - uECC_word_t _3[uECC_MAX_WORDS] = {3}; /* -a = 3 */ - wordcount_t num_words = curve->num_words; - - uECC_vli_modSquare_fast(result, x, curve); /* r = x^2 */ - uECC_vli_modSub(result, result, _3, curve->p, num_words); /* r = x^2 - 3 */ - uECC_vli_modMult_fast(result, result, x, curve); /* r = x^3 - 3x */ - uECC_vli_modAdd(result, result, curve->b, curve->p, num_words); /* r = x^3 - 3x + b */ -} -#endif /* uECC_SUPPORTS_secp... */ - -#if uECC_SUPPORT_COMPRESSED_POINT -#if uECC_SUPPORTS_secp160r1 || uECC_SUPPORTS_secp192r1 || \ - uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1 -/* Compute a = sqrt(a) (mod curve_p). */ -static void mod_sqrt_default(uECC_word_t *a, uECC_Curve curve) { - bitcount_t i; - uECC_word_t p1[uECC_MAX_WORDS] = {1}; - uECC_word_t l_result[uECC_MAX_WORDS] = {1}; - wordcount_t num_words = curve->num_words; - - /* When curve->p == 3 (mod 4), we can compute - sqrt(a) = a^((curve->p + 1) / 4) (mod curve->p). */ - uECC_vli_add(p1, curve->p, p1, num_words); /* p1 = curve_p + 1 */ - for (i = uECC_vli_numBits(p1, num_words) - 1; i > 1; --i) { - uECC_vli_modSquare_fast(l_result, l_result, curve); - if (uECC_vli_testBit(p1, i)) { - uECC_vli_modMult_fast(l_result, l_result, a, curve); - } - } - uECC_vli_set(a, l_result, num_words); -} -#endif /* uECC_SUPPORTS_secp... */ -#endif /* uECC_SUPPORT_COMPRESSED_POINT */ - -#if uECC_SUPPORTS_secp160r1 - -#if (uECC_OPTIMIZATION_LEVEL > 0) -static void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product); -#endif - -static const struct uECC_Curve_t curve_secp160r1 = { - num_words_secp160r1, - num_bytes_secp160r1, - 161, /* num_n_bits */ - { BYTES_TO_WORDS_8(FF, FF, FF, 7F, FF, FF, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_4(FF, FF, FF, FF) }, - { BYTES_TO_WORDS_8(57, 22, 75, CA, D3, AE, 27, F9), - BYTES_TO_WORDS_8(C8, F4, 01, 00, 00, 00, 00, 00), - BYTES_TO_WORDS_8(00, 00, 00, 00, 01, 00, 00, 00) }, - { BYTES_TO_WORDS_8(82, FC, CB, 13, B9, 8B, C3, 68), - BYTES_TO_WORDS_8(89, 69, 64, 46, 28, 73, F5, 8E), - BYTES_TO_WORDS_4(68, B5, 96, 4A), - - BYTES_TO_WORDS_8(32, FB, C5, 7A, 37, 51, 23, 04), - BYTES_TO_WORDS_8(12, C9, DC, 59, 7D, 94, 68, 31), - BYTES_TO_WORDS_4(55, 28, A6, 23) }, - { BYTES_TO_WORDS_8(45, FA, 65, C5, AD, D4, D4, 81), - BYTES_TO_WORDS_8(9F, F8, AC, 65, 8B, 7A, BD, 54), - BYTES_TO_WORDS_4(FC, BE, 97, 1C) }, - &double_jacobian_default, -#if uECC_SUPPORT_COMPRESSED_POINT - &mod_sqrt_default, -#endif - &x_side_default, -#if (uECC_OPTIMIZATION_LEVEL > 0) - &vli_mmod_fast_secp160r1 -#endif -}; - -uECC_Curve uECC_secp160r1(void) { return &curve_secp160r1; } - -#if (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp160r1) -/* Computes result = product % curve_p - see http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf page 354 - - Note that this only works if log2(omega) < log2(p) / 2 */ -static void omega_mult_secp160r1(uECC_word_t *result, const uECC_word_t *right); -#if uECC_WORD_SIZE == 8 -static void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product) { - uECC_word_t tmp[2 * num_words_secp160r1]; - uECC_word_t copy; - - uECC_vli_clear(tmp, num_words_secp160r1); - uECC_vli_clear(tmp + num_words_secp160r1, num_words_secp160r1); - - omega_mult_secp160r1(tmp, product + num_words_secp160r1 - 1); /* (Rq, q) = q * c */ - - product[num_words_secp160r1 - 1] &= 0xffffffff; - copy = tmp[num_words_secp160r1 - 1]; - tmp[num_words_secp160r1 - 1] &= 0xffffffff; - uECC_vli_add(result, product, tmp, num_words_secp160r1); /* (C, r) = r + q */ - uECC_vli_clear(product, num_words_secp160r1); - tmp[num_words_secp160r1 - 1] = copy; - omega_mult_secp160r1(product, tmp + num_words_secp160r1 - 1); /* Rq*c */ - uECC_vli_add(result, result, product, num_words_secp160r1); /* (C1, r) = r + Rq*c */ - - while (uECC_vli_cmp_unsafe(result, curve_secp160r1.p, num_words_secp160r1) > 0) { - uECC_vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1); - } -} - -static void omega_mult_secp160r1(uint64_t *result, const uint64_t *right) { - uint32_t carry; - unsigned i; - - /* Multiply by (2^31 + 1). */ - carry = 0; - for (i = 0; i < num_words_secp160r1; ++i) { - uint64_t tmp = (right[i] >> 32) | (right[i + 1] << 32); - result[i] = (tmp << 31) + tmp + carry; - carry = (tmp >> 33) + (result[i] < tmp || (carry && result[i] == tmp)); - } - result[i] = carry; -} -#else -static void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product) { - uECC_word_t tmp[2 * num_words_secp160r1]; - uECC_word_t carry; - - uECC_vli_clear(tmp, num_words_secp160r1); - uECC_vli_clear(tmp + num_words_secp160r1, num_words_secp160r1); - - omega_mult_secp160r1(tmp, product + num_words_secp160r1); /* (Rq, q) = q * c */ - - carry = uECC_vli_add(result, product, tmp, num_words_secp160r1); /* (C, r) = r + q */ - uECC_vli_clear(product, num_words_secp160r1); - omega_mult_secp160r1(product, tmp + num_words_secp160r1); /* Rq*c */ - carry += uECC_vli_add(result, result, product, num_words_secp160r1); /* (C1, r) = r + Rq*c */ - - while (carry > 0) { - --carry; - uECC_vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1); - } - if (uECC_vli_cmp_unsafe(result, curve_secp160r1.p, num_words_secp160r1) > 0) { - uECC_vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1); - } -} -#endif - -#if uECC_WORD_SIZE == 1 -static void omega_mult_secp160r1(uint8_t *result, const uint8_t *right) { - uint8_t carry; - uint8_t i; - - /* Multiply by (2^31 + 1). */ - uECC_vli_set(result + 4, right, num_words_secp160r1); /* 2^32 */ - uECC_vli_rshift1(result + 4, num_words_secp160r1); /* 2^31 */ - result[3] = right[0] << 7; /* get last bit from shift */ - - carry = uECC_vli_add(result, result, right, num_words_secp160r1); /* 2^31 + 1 */ - for (i = num_words_secp160r1; carry; ++i) { - uint16_t sum = (uint16_t)result[i] + carry; - result[i] = (uint8_t)sum; - carry = sum >> 8; - } -} -#elif uECC_WORD_SIZE == 4 -static void omega_mult_secp160r1(uint32_t *result, const uint32_t *right) { - uint32_t carry; - unsigned i; - - /* Multiply by (2^31 + 1). */ - uECC_vli_set(result + 1, right, num_words_secp160r1); /* 2^32 */ - uECC_vli_rshift1(result + 1, num_words_secp160r1); /* 2^31 */ - result[0] = right[0] << 31; /* get last bit from shift */ - - carry = uECC_vli_add(result, result, right, num_words_secp160r1); /* 2^31 + 1 */ - for (i = num_words_secp160r1; carry; ++i) { - uint64_t sum = (uint64_t)result[i] + carry; - result[i] = (uint32_t)sum; - carry = sum >> 32; - } -} -#endif /* uECC_WORD_SIZE */ -#endif /* (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp160r1) */ - -#endif /* uECC_SUPPORTS_secp160r1 */ - -#if uECC_SUPPORTS_secp192r1 - -#if (uECC_OPTIMIZATION_LEVEL > 0) -static void vli_mmod_fast_secp192r1(uECC_word_t *result, uECC_word_t *product); -#endif - -static const struct uECC_Curve_t curve_secp192r1 = { - num_words_secp192r1, - num_bytes_secp192r1, - 192, /* num_n_bits */ - { BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_8(FE, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) }, - { BYTES_TO_WORDS_8(31, 28, D2, B4, B1, C9, 6B, 14), - BYTES_TO_WORDS_8(36, F8, DE, 99, FF, FF, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) }, - { BYTES_TO_WORDS_8(12, 10, FF, 82, FD, 0A, FF, F4), - BYTES_TO_WORDS_8(00, 88, A1, 43, EB, 20, BF, 7C), - BYTES_TO_WORDS_8(F6, 90, 30, B0, 0E, A8, 8D, 18), - - BYTES_TO_WORDS_8(11, 48, 79, 1E, A1, 77, F9, 73), - BYTES_TO_WORDS_8(D5, CD, 24, 6B, ED, 11, 10, 63), - BYTES_TO_WORDS_8(78, DA, C8, FF, 95, 2B, 19, 07) }, - { BYTES_TO_WORDS_8(B1, B9, 46, C1, EC, DE, B8, FE), - BYTES_TO_WORDS_8(49, 30, 24, 72, AB, E9, A7, 0F), - BYTES_TO_WORDS_8(E7, 80, 9C, E5, 19, 05, 21, 64) }, - &double_jacobian_default, -#if uECC_SUPPORT_COMPRESSED_POINT - &mod_sqrt_default, -#endif - &x_side_default, -#if (uECC_OPTIMIZATION_LEVEL > 0) - &vli_mmod_fast_secp192r1 -#endif -}; - -uECC_Curve uECC_secp192r1(void) { return &curve_secp192r1; } - -#if (uECC_OPTIMIZATION_LEVEL > 0) -/* Computes result = product % curve_p. - See algorithm 5 and 6 from http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf */ -#if uECC_WORD_SIZE == 1 -static void vli_mmod_fast_secp192r1(uint8_t *result, uint8_t *product) { - uint8_t tmp[num_words_secp192r1]; - uint8_t carry; - - uECC_vli_set(result, product, num_words_secp192r1); - - uECC_vli_set(tmp, &product[24], num_words_secp192r1); - carry = uECC_vli_add(result, result, tmp, num_words_secp192r1); - - tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0; - tmp[8] = product[24]; tmp[9] = product[25]; tmp[10] = product[26]; tmp[11] = product[27]; - tmp[12] = product[28]; tmp[13] = product[29]; tmp[14] = product[30]; tmp[15] = product[31]; - tmp[16] = product[32]; tmp[17] = product[33]; tmp[18] = product[34]; tmp[19] = product[35]; - tmp[20] = product[36]; tmp[21] = product[37]; tmp[22] = product[38]; tmp[23] = product[39]; - carry += uECC_vli_add(result, result, tmp, num_words_secp192r1); - - tmp[0] = tmp[8] = product[40]; - tmp[1] = tmp[9] = product[41]; - tmp[2] = tmp[10] = product[42]; - tmp[3] = tmp[11] = product[43]; - tmp[4] = tmp[12] = product[44]; - tmp[5] = tmp[13] = product[45]; - tmp[6] = tmp[14] = product[46]; - tmp[7] = tmp[15] = product[47]; - tmp[16] = tmp[17] = tmp[18] = tmp[19] = tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0; - carry += uECC_vli_add(result, result, tmp, num_words_secp192r1); - - while (carry || uECC_vli_cmp_unsafe(curve_secp192r1.p, result, num_words_secp192r1) != 1) { - carry -= uECC_vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1); - } -} -#elif uECC_WORD_SIZE == 4 -static void vli_mmod_fast_secp192r1(uint32_t *result, uint32_t *product) { - uint32_t tmp[num_words_secp192r1]; - int carry; - - uECC_vli_set(result, product, num_words_secp192r1); - - uECC_vli_set(tmp, &product[6], num_words_secp192r1); - carry = uECC_vli_add(result, result, tmp, num_words_secp192r1); - - tmp[0] = tmp[1] = 0; - tmp[2] = product[6]; - tmp[3] = product[7]; - tmp[4] = product[8]; - tmp[5] = product[9]; - carry += uECC_vli_add(result, result, tmp, num_words_secp192r1); - - tmp[0] = tmp[2] = product[10]; - tmp[1] = tmp[3] = product[11]; - tmp[4] = tmp[5] = 0; - carry += uECC_vli_add(result, result, tmp, num_words_secp192r1); - - while (carry || uECC_vli_cmp_unsafe(curve_secp192r1.p, result, num_words_secp192r1) != 1) { - carry -= uECC_vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1); - } -} -#else -static void vli_mmod_fast_secp192r1(uint64_t *result, uint64_t *product) { - uint64_t tmp[num_words_secp192r1]; - int carry; - - uECC_vli_set(result, product, num_words_secp192r1); - - uECC_vli_set(tmp, &product[3], num_words_secp192r1); - carry = (int)uECC_vli_add(result, result, tmp, num_words_secp192r1); - - tmp[0] = 0; - tmp[1] = product[3]; - tmp[2] = product[4]; - carry += uECC_vli_add(result, result, tmp, num_words_secp192r1); - - tmp[0] = tmp[1] = product[5]; - tmp[2] = 0; - carry += uECC_vli_add(result, result, tmp, num_words_secp192r1); - - while (carry || uECC_vli_cmp_unsafe(curve_secp192r1.p, result, num_words_secp192r1) != 1) { - carry -= uECC_vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1); - } -} -#endif /* uECC_WORD_SIZE */ -#endif /* (uECC_OPTIMIZATION_LEVEL > 0) */ - -#endif /* uECC_SUPPORTS_secp192r1 */ - -#if uECC_SUPPORTS_secp224r1 - -#if uECC_SUPPORT_COMPRESSED_POINT -static void mod_sqrt_secp224r1(uECC_word_t *a, uECC_Curve curve); -#endif -#if (uECC_OPTIMIZATION_LEVEL > 0) -static void vli_mmod_fast_secp224r1(uECC_word_t *result, uECC_word_t *product); -#endif - -static const struct uECC_Curve_t curve_secp224r1 = { - num_words_secp224r1, - num_bytes_secp224r1, - 224, /* num_n_bits */ - { BYTES_TO_WORDS_8(01, 00, 00, 00, 00, 00, 00, 00), - BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_4(FF, FF, FF, FF) }, - { BYTES_TO_WORDS_8(3D, 2A, 5C, 5C, 45, 29, DD, 13), - BYTES_TO_WORDS_8(3E, F0, B8, E0, A2, 16, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_4(FF, FF, FF, FF) }, - { BYTES_TO_WORDS_8(21, 1D, 5C, 11, D6, 80, 32, 34), - BYTES_TO_WORDS_8(22, 11, C2, 56, D3, C1, 03, 4A), - BYTES_TO_WORDS_8(B9, 90, 13, 32, 7F, BF, B4, 6B), - BYTES_TO_WORDS_4(BD, 0C, 0E, B7), - - BYTES_TO_WORDS_8(34, 7E, 00, 85, 99, 81, D5, 44), - BYTES_TO_WORDS_8(64, 47, 07, 5A, A0, 75, 43, CD), - BYTES_TO_WORDS_8(E6, DF, 22, 4C, FB, 23, F7, B5), - BYTES_TO_WORDS_4(88, 63, 37, BD) }, - { BYTES_TO_WORDS_8(B4, FF, 55, 23, 43, 39, 0B, 27), - BYTES_TO_WORDS_8(BA, D8, BF, D7, B7, B0, 44, 50), - BYTES_TO_WORDS_8(56, 32, 41, F5, AB, B3, 04, 0C), - BYTES_TO_WORDS_4(85, 0A, 05, B4) }, - &double_jacobian_default, -#if uECC_SUPPORT_COMPRESSED_POINT - &mod_sqrt_secp224r1, -#endif - &x_side_default, -#if (uECC_OPTIMIZATION_LEVEL > 0) - &vli_mmod_fast_secp224r1 -#endif -}; - -uECC_Curve uECC_secp224r1(void) { return &curve_secp224r1; } - - -#if uECC_SUPPORT_COMPRESSED_POINT -/* Routine 3.2.4 RS; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ -static void mod_sqrt_secp224r1_rs(uECC_word_t *d1, - uECC_word_t *e1, - uECC_word_t *f1, - const uECC_word_t *d0, - const uECC_word_t *e0, - const uECC_word_t *f0) { - uECC_word_t t[num_words_secp224r1]; - - uECC_vli_modSquare_fast(t, d0, &curve_secp224r1); /* t <-- d0 ^ 2 */ - uECC_vli_modMult_fast(e1, d0, e0, &curve_secp224r1); /* e1 <-- d0 * e0 */ - uECC_vli_modAdd(d1, t, f0, curve_secp224r1.p, num_words_secp224r1); /* d1 <-- t + f0 */ - uECC_vli_modAdd(e1, e1, e1, curve_secp224r1.p, num_words_secp224r1); /* e1 <-- e1 + e1 */ - uECC_vli_modMult_fast(f1, t, f0, &curve_secp224r1); /* f1 <-- t * f0 */ - uECC_vli_modAdd(f1, f1, f1, curve_secp224r1.p, num_words_secp224r1); /* f1 <-- f1 + f1 */ - uECC_vli_modAdd(f1, f1, f1, curve_secp224r1.p, num_words_secp224r1); /* f1 <-- f1 + f1 */ -} - -/* Routine 3.2.5 RSS; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ -static void mod_sqrt_secp224r1_rss(uECC_word_t *d1, - uECC_word_t *e1, - uECC_word_t *f1, - const uECC_word_t *d0, - const uECC_word_t *e0, - const uECC_word_t *f0, - const bitcount_t j) { - bitcount_t i; - - uECC_vli_set(d1, d0, num_words_secp224r1); /* d1 <-- d0 */ - uECC_vli_set(e1, e0, num_words_secp224r1); /* e1 <-- e0 */ - uECC_vli_set(f1, f0, num_words_secp224r1); /* f1 <-- f0 */ - for (i = 1; i <= j; i++) { - mod_sqrt_secp224r1_rs(d1, e1, f1, d1, e1, f1); /* RS (d1,e1,f1,d1,e1,f1) */ - } -} - -/* Routine 3.2.6 RM; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ -static void mod_sqrt_secp224r1_rm(uECC_word_t *d2, - uECC_word_t *e2, - uECC_word_t *f2, - const uECC_word_t *c, - const uECC_word_t *d0, - const uECC_word_t *e0, - const uECC_word_t *d1, - const uECC_word_t *e1) { - uECC_word_t t1[num_words_secp224r1]; - uECC_word_t t2[num_words_secp224r1]; - - uECC_vli_modMult_fast(t1, e0, e1, &curve_secp224r1); /* t1 <-- e0 * e1 */ - uECC_vli_modMult_fast(t1, t1, c, &curve_secp224r1); /* t1 <-- t1 * c */ - /* t1 <-- p - t1 */ - uECC_vli_modSub(t1, curve_secp224r1.p, t1, curve_secp224r1.p, num_words_secp224r1); - uECC_vli_modMult_fast(t2, d0, d1, &curve_secp224r1); /* t2 <-- d0 * d1 */ - uECC_vli_modAdd(t2, t2, t1, curve_secp224r1.p, num_words_secp224r1); /* t2 <-- t2 + t1 */ - uECC_vli_modMult_fast(t1, d0, e1, &curve_secp224r1); /* t1 <-- d0 * e1 */ - uECC_vli_modMult_fast(e2, d1, e0, &curve_secp224r1); /* e2 <-- d1 * e0 */ - uECC_vli_modAdd(e2, e2, t1, curve_secp224r1.p, num_words_secp224r1); /* e2 <-- e2 + t1 */ - uECC_vli_modSquare_fast(f2, e2, &curve_secp224r1); /* f2 <-- e2^2 */ - uECC_vli_modMult_fast(f2, f2, c, &curve_secp224r1); /* f2 <-- f2 * c */ - /* f2 <-- p - f2 */ - uECC_vli_modSub(f2, curve_secp224r1.p, f2, curve_secp224r1.p, num_words_secp224r1); - uECC_vli_set(d2, t2, num_words_secp224r1); /* d2 <-- t2 */ -} - -/* Routine 3.2.7 RP; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ -static void mod_sqrt_secp224r1_rp(uECC_word_t *d1, - uECC_word_t *e1, - uECC_word_t *f1, - const uECC_word_t *c, - const uECC_word_t *r) { - wordcount_t i; - wordcount_t pow2i = 1; - uECC_word_t d0[num_words_secp224r1]; - uECC_word_t e0[num_words_secp224r1] = {1}; /* e0 <-- 1 */ - uECC_word_t f0[num_words_secp224r1]; - - uECC_vli_set(d0, r, num_words_secp224r1); /* d0 <-- r */ - /* f0 <-- p - c */ - uECC_vli_modSub(f0, curve_secp224r1.p, c, curve_secp224r1.p, num_words_secp224r1); - for (i = 0; i <= 6; i++) { - mod_sqrt_secp224r1_rss(d1, e1, f1, d0, e0, f0, pow2i); /* RSS (d1,e1,f1,d0,e0,f0,2^i) */ - mod_sqrt_secp224r1_rm(d1, e1, f1, c, d1, e1, d0, e0); /* RM (d1,e1,f1,c,d1,e1,d0,e0) */ - uECC_vli_set(d0, d1, num_words_secp224r1); /* d0 <-- d1 */ - uECC_vli_set(e0, e1, num_words_secp224r1); /* e0 <-- e1 */ - uECC_vli_set(f0, f1, num_words_secp224r1); /* f0 <-- f1 */ - pow2i *= 2; - } -} - -/* Compute a = sqrt(a) (mod curve_p). */ -/* Routine 3.2.8 mp_mod_sqrt_224; from http://www.nsa.gov/ia/_files/nist-routines.pdf */ -static void mod_sqrt_secp224r1(uECC_word_t *a, uECC_Curve curve) { - (void)curve; - bitcount_t i; - uECC_word_t e1[num_words_secp224r1]; - uECC_word_t f1[num_words_secp224r1]; - uECC_word_t d0[num_words_secp224r1]; - uECC_word_t e0[num_words_secp224r1]; - uECC_word_t f0[num_words_secp224r1]; - uECC_word_t d1[num_words_secp224r1]; - - /* s = a; using constant instead of random value */ - mod_sqrt_secp224r1_rp(d0, e0, f0, a, a); /* RP (d0, e0, f0, c, s) */ - mod_sqrt_secp224r1_rs(d1, e1, f1, d0, e0, f0); /* RS (d1, e1, f1, d0, e0, f0) */ - for (i = 1; i <= 95; i++) { - uECC_vli_set(d0, d1, num_words_secp224r1); /* d0 <-- d1 */ - uECC_vli_set(e0, e1, num_words_secp224r1); /* e0 <-- e1 */ - uECC_vli_set(f0, f1, num_words_secp224r1); /* f0 <-- f1 */ - mod_sqrt_secp224r1_rs(d1, e1, f1, d0, e0, f0); /* RS (d1, e1, f1, d0, e0, f0) */ - if (uECC_vli_isZero(d1, num_words_secp224r1)) { /* if d1 == 0 */ - break; - } - } - uECC_vli_modInv(f1, e0, curve_secp224r1.p, num_words_secp224r1); /* f1 <-- 1 / e0 */ - uECC_vli_modMult_fast(a, d0, f1, &curve_secp224r1); /* a <-- d0 / e0 */ -} -#endif /* uECC_SUPPORT_COMPRESSED_POINT */ - -#if (uECC_OPTIMIZATION_LEVEL > 0) -/* Computes result = product % curve_p - from http://www.nsa.gov/ia/_files/nist-routines.pdf */ -#if uECC_WORD_SIZE == 1 -static void vli_mmod_fast_secp224r1(uint8_t *result, uint8_t *product) { - uint8_t tmp[num_words_secp224r1]; - int8_t carry; - - /* t */ - uECC_vli_set(result, product, num_words_secp224r1); - - /* s1 */ - tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0; - tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0; - tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0; - tmp[12] = product[28]; tmp[13] = product[29]; tmp[14] = product[30]; tmp[15] = product[31]; - tmp[16] = product[32]; tmp[17] = product[33]; tmp[18] = product[34]; tmp[19] = product[35]; - tmp[20] = product[36]; tmp[21] = product[37]; tmp[22] = product[38]; tmp[23] = product[39]; - tmp[24] = product[40]; tmp[25] = product[41]; tmp[26] = product[42]; tmp[27] = product[43]; - carry = uECC_vli_add(result, result, tmp, num_words_secp224r1); - - /* s2 */ - tmp[12] = product[44]; tmp[13] = product[45]; tmp[14] = product[46]; tmp[15] = product[47]; - tmp[16] = product[48]; tmp[17] = product[49]; tmp[18] = product[50]; tmp[19] = product[51]; - tmp[20] = product[52]; tmp[21] = product[53]; tmp[22] = product[54]; tmp[23] = product[55]; - tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0; - carry += uECC_vli_add(result, result, tmp, num_words_secp224r1); - - /* d1 */ - tmp[0] = product[28]; tmp[1] = product[29]; tmp[2] = product[30]; tmp[3] = product[31]; - tmp[4] = product[32]; tmp[5] = product[33]; tmp[6] = product[34]; tmp[7] = product[35]; - tmp[8] = product[36]; tmp[9] = product[37]; tmp[10] = product[38]; tmp[11] = product[39]; - tmp[12] = product[40]; tmp[13] = product[41]; tmp[14] = product[42]; tmp[15] = product[43]; - tmp[16] = product[44]; tmp[17] = product[45]; tmp[18] = product[46]; tmp[19] = product[47]; - tmp[20] = product[48]; tmp[21] = product[49]; tmp[22] = product[50]; tmp[23] = product[51]; - tmp[24] = product[52]; tmp[25] = product[53]; tmp[26] = product[54]; tmp[27] = product[55]; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1); - - /* d2 */ - tmp[0] = product[44]; tmp[1] = product[45]; tmp[2] = product[46]; tmp[3] = product[47]; - tmp[4] = product[48]; tmp[5] = product[49]; tmp[6] = product[50]; tmp[7] = product[51]; - tmp[8] = product[52]; tmp[9] = product[53]; tmp[10] = product[54]; tmp[11] = product[55]; - tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0; - tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0; - tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0; - tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1); - - if (carry < 0) { - do { - carry += uECC_vli_add(result, result, curve_secp224r1.p, num_words_secp224r1); - } while (carry < 0); - } else { - while (carry || uECC_vli_cmp_unsafe(curve_secp224r1.p, result, num_words_secp224r1) != 1) { - carry -= uECC_vli_sub(result, result, curve_secp224r1.p, num_words_secp224r1); - } - } -} -#elif uECC_WORD_SIZE == 4 -static void vli_mmod_fast_secp224r1(uint32_t *result, uint32_t *product) -{ - uint32_t tmp[num_words_secp224r1]; - int carry; - - /* t */ - uECC_vli_set(result, product, num_words_secp224r1); - - /* s1 */ - tmp[0] = tmp[1] = tmp[2] = 0; - tmp[3] = product[7]; - tmp[4] = product[8]; - tmp[5] = product[9]; - tmp[6] = product[10]; - carry = uECC_vli_add(result, result, tmp, num_words_secp224r1); - - /* s2 */ - tmp[3] = product[11]; - tmp[4] = product[12]; - tmp[5] = product[13]; - tmp[6] = 0; - carry += uECC_vli_add(result, result, tmp, num_words_secp224r1); - - /* d1 */ - tmp[0] = product[7]; - tmp[1] = product[8]; - tmp[2] = product[9]; - tmp[3] = product[10]; - tmp[4] = product[11]; - tmp[5] = product[12]; - tmp[6] = product[13]; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1); - - /* d2 */ - tmp[0] = product[11]; - tmp[1] = product[12]; - tmp[2] = product[13]; - tmp[3] = tmp[4] = tmp[5] = tmp[6] = 0; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1); - - if (carry < 0) { - do { - carry += uECC_vli_add(result, result, curve_secp224r1.p, num_words_secp224r1); - } while (carry < 0); - } else { - while (carry || uECC_vli_cmp_unsafe(curve_secp224r1.p, result, num_words_secp224r1) != 1) { - carry -= uECC_vli_sub(result, result, curve_secp224r1.p, num_words_secp224r1); - } - } -} -#else -static void vli_mmod_fast_secp224r1(uint64_t *result, uint64_t *product) -{ - uint64_t tmp[num_words_secp224r1]; - int carry = 0; - - /* t */ - uECC_vli_set(result, product, num_words_secp224r1); - result[num_words_secp224r1 - 1] &= 0xffffffff; - - /* s1 */ - tmp[0] = 0; - tmp[1] = product[3] & 0xffffffff00000000ull; - tmp[2] = product[4]; - tmp[3] = product[5] & 0xffffffff; - uECC_vli_add(result, result, tmp, num_words_secp224r1); - - /* s2 */ - tmp[1] = product[5] & 0xffffffff00000000ull; - tmp[2] = product[6]; - tmp[3] = 0; - uECC_vli_add(result, result, tmp, num_words_secp224r1); - - /* d1 */ - tmp[0] = (product[3] >> 32) | (product[4] << 32); - tmp[1] = (product[4] >> 32) | (product[5] << 32); - tmp[2] = (product[5] >> 32) | (product[6] << 32); - tmp[3] = product[6] >> 32; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1); - - /* d2 */ - tmp[0] = (product[5] >> 32) | (product[6] << 32); - tmp[1] = product[6] >> 32; - tmp[2] = tmp[3] = 0; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp224r1); - - if (carry < 0) { - do { - carry += uECC_vli_add(result, result, curve_secp224r1.p, num_words_secp224r1); - } while (carry < 0); - } else { - while (uECC_vli_cmp_unsafe(curve_secp224r1.p, result, num_words_secp224r1) != 1) { - uECC_vli_sub(result, result, curve_secp224r1.p, num_words_secp224r1); - } - } -} -#endif /* uECC_WORD_SIZE */ -#endif /* (uECC_OPTIMIZATION_LEVEL > 0) */ - -#endif /* uECC_SUPPORTS_secp224r1 */ - -#if uECC_SUPPORTS_secp256r1 - -#if (uECC_OPTIMIZATION_LEVEL > 0) -static void vli_mmod_fast_secp256r1(uECC_word_t *result, uECC_word_t *product); -#endif - -static const struct uECC_Curve_t curve_secp256r1 = { - num_words_secp256r1, - num_bytes_secp256r1, - 256, /* num_n_bits */ - { BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, 00, 00, 00, 00), - BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00), - BYTES_TO_WORDS_8(01, 00, 00, 00, FF, FF, FF, FF) }, - { BYTES_TO_WORDS_8(51, 25, 63, FC, C2, CA, B9, F3), - BYTES_TO_WORDS_8(84, 9E, 17, A7, AD, FA, E6, BC), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF) }, - { BYTES_TO_WORDS_8(96, C2, 98, D8, 45, 39, A1, F4), - BYTES_TO_WORDS_8(A0, 33, EB, 2D, 81, 7D, 03, 77), - BYTES_TO_WORDS_8(F2, 40, A4, 63, E5, E6, BC, F8), - BYTES_TO_WORDS_8(47, 42, 2C, E1, F2, D1, 17, 6B), - - BYTES_TO_WORDS_8(F5, 51, BF, 37, 68, 40, B6, CB), - BYTES_TO_WORDS_8(CE, 5E, 31, 6B, 57, 33, CE, 2B), - BYTES_TO_WORDS_8(16, 9E, 0F, 7C, 4A, EB, E7, 8E), - BYTES_TO_WORDS_8(9B, 7F, 1A, FE, E2, 42, E3, 4F) }, - { BYTES_TO_WORDS_8(4B, 60, D2, 27, 3E, 3C, CE, 3B), - BYTES_TO_WORDS_8(F6, B0, 53, CC, B0, 06, 1D, 65), - BYTES_TO_WORDS_8(BC, 86, 98, 76, 55, BD, EB, B3), - BYTES_TO_WORDS_8(E7, 93, 3A, AA, D8, 35, C6, 5A) }, - &double_jacobian_default, -#if uECC_SUPPORT_COMPRESSED_POINT - &mod_sqrt_default, -#endif - &x_side_default, -#if (uECC_OPTIMIZATION_LEVEL > 0) - &vli_mmod_fast_secp256r1 -#endif -}; - -uECC_Curve uECC_secp256r1(void) { return &curve_secp256r1; } - - -#if (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp256r1) -/* Computes result = product % curve_p - from http://www.nsa.gov/ia/_files/nist-routines.pdf */ -#if uECC_WORD_SIZE == 1 -static void vli_mmod_fast_secp256r1(uint8_t *result, uint8_t *product) { - uint8_t tmp[num_words_secp256r1]; - int8_t carry; - - /* t */ - uECC_vli_set(result, product, num_words_secp256r1); - - /* s1 */ - tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0; - tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0; - tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0; - tmp[12] = product[44]; tmp[13] = product[45]; tmp[14] = product[46]; tmp[15] = product[47]; - tmp[16] = product[48]; tmp[17] = product[49]; tmp[18] = product[50]; tmp[19] = product[51]; - tmp[20] = product[52]; tmp[21] = product[53]; tmp[22] = product[54]; tmp[23] = product[55]; - tmp[24] = product[56]; tmp[25] = product[57]; tmp[26] = product[58]; tmp[27] = product[59]; - tmp[28] = product[60]; tmp[29] = product[61]; tmp[30] = product[62]; tmp[31] = product[63]; - carry = uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* s2 */ - tmp[12] = product[48]; tmp[13] = product[49]; tmp[14] = product[50]; tmp[15] = product[51]; - tmp[16] = product[52]; tmp[17] = product[53]; tmp[18] = product[54]; tmp[19] = product[55]; - tmp[20] = product[56]; tmp[21] = product[57]; tmp[22] = product[58]; tmp[23] = product[59]; - tmp[24] = product[60]; tmp[25] = product[61]; tmp[26] = product[62]; tmp[27] = product[63]; - tmp[28] = tmp[29] = tmp[30] = tmp[31] = 0; - carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* s3 */ - tmp[0] = product[32]; tmp[1] = product[33]; tmp[2] = product[34]; tmp[3] = product[35]; - tmp[4] = product[36]; tmp[5] = product[37]; tmp[6] = product[38]; tmp[7] = product[39]; - tmp[8] = product[40]; tmp[9] = product[41]; tmp[10] = product[42]; tmp[11] = product[43]; - tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0; - tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0; - tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0; - tmp[24] = product[56]; tmp[25] = product[57]; tmp[26] = product[58]; tmp[27] = product[59]; - tmp[28] = product[60]; tmp[29] = product[61]; tmp[30] = product[62]; tmp[31] = product[63]; - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* s4 */ - tmp[0] = product[36]; tmp[1] = product[37]; tmp[2] = product[38]; tmp[3] = product[39]; - tmp[4] = product[40]; tmp[5] = product[41]; tmp[6] = product[42]; tmp[7] = product[43]; - tmp[8] = product[44]; tmp[9] = product[45]; tmp[10] = product[46]; tmp[11] = product[47]; - tmp[12] = product[52]; tmp[13] = product[53]; tmp[14] = product[54]; tmp[15] = product[55]; - tmp[16] = product[56]; tmp[17] = product[57]; tmp[18] = product[58]; tmp[19] = product[59]; - tmp[20] = product[60]; tmp[21] = product[61]; tmp[22] = product[62]; tmp[23] = product[63]; - tmp[24] = product[52]; tmp[25] = product[53]; tmp[26] = product[54]; tmp[27] = product[55]; - tmp[28] = product[32]; tmp[29] = product[33]; tmp[30] = product[34]; tmp[31] = product[35]; - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* d1 */ - tmp[0] = product[44]; tmp[1] = product[45]; tmp[2] = product[46]; tmp[3] = product[47]; - tmp[4] = product[48]; tmp[5] = product[49]; tmp[6] = product[50]; tmp[7] = product[51]; - tmp[8] = product[52]; tmp[9] = product[53]; tmp[10] = product[54]; tmp[11] = product[55]; - tmp[12] = tmp[13] = tmp[14] = tmp[15] = 0; - tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0; - tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0; - tmp[24] = product[32]; tmp[25] = product[33]; tmp[26] = product[34]; tmp[27] = product[35]; - tmp[28] = product[40]; tmp[29] = product[41]; tmp[30] = product[42]; tmp[31] = product[43]; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - /* d2 */ - tmp[0] = product[48]; tmp[1] = product[49]; tmp[2] = product[50]; tmp[3] = product[51]; - tmp[4] = product[52]; tmp[5] = product[53]; tmp[6] = product[54]; tmp[7] = product[55]; - tmp[8] = product[56]; tmp[9] = product[57]; tmp[10] = product[58]; tmp[11] = product[59]; - tmp[12] = product[60]; tmp[13] = product[61]; tmp[14] = product[62]; tmp[15] = product[63]; - tmp[16] = tmp[17] = tmp[18] = tmp[19] = 0; - tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0; - tmp[24] = product[36]; tmp[25] = product[37]; tmp[26] = product[38]; tmp[27] = product[39]; - tmp[28] = product[44]; tmp[29] = product[45]; tmp[30] = product[46]; tmp[31] = product[47]; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - /* d3 */ - tmp[0] = product[52]; tmp[1] = product[53]; tmp[2] = product[54]; tmp[3] = product[55]; - tmp[4] = product[56]; tmp[5] = product[57]; tmp[6] = product[58]; tmp[7] = product[59]; - tmp[8] = product[60]; tmp[9] = product[61]; tmp[10] = product[62]; tmp[11] = product[63]; - tmp[12] = product[32]; tmp[13] = product[33]; tmp[14] = product[34]; tmp[15] = product[35]; - tmp[16] = product[36]; tmp[17] = product[37]; tmp[18] = product[38]; tmp[19] = product[39]; - tmp[20] = product[40]; tmp[21] = product[41]; tmp[22] = product[42]; tmp[23] = product[43]; - tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0; - tmp[28] = product[48]; tmp[29] = product[49]; tmp[30] = product[50]; tmp[31] = product[51]; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - /* d4 */ - tmp[0] = product[56]; tmp[1] = product[57]; tmp[2] = product[58]; tmp[3] = product[59]; - tmp[4] = product[60]; tmp[5] = product[61]; tmp[6] = product[62]; tmp[7] = product[63]; - tmp[8] = tmp[9] = tmp[10] = tmp[11] = 0; - tmp[12] = product[36]; tmp[13] = product[37]; tmp[14] = product[38]; tmp[15] = product[39]; - tmp[16] = product[40]; tmp[17] = product[41]; tmp[18] = product[42]; tmp[19] = product[43]; - tmp[20] = product[44]; tmp[21] = product[45]; tmp[22] = product[46]; tmp[23] = product[47]; - tmp[24] = tmp[25] = tmp[26] = tmp[27] = 0; - tmp[28] = product[52]; tmp[29] = product[53]; tmp[30] = product[54]; tmp[31] = product[55]; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - if (carry < 0) { - do { - carry += uECC_vli_add(result, result, curve_secp256r1.p, num_words_secp256r1); - } while (carry < 0); - } else { - while (carry || uECC_vli_cmp_unsafe(curve_secp256r1.p, result, num_words_secp256r1) != 1) { - carry -= uECC_vli_sub(result, result, curve_secp256r1.p, num_words_secp256r1); - } - } -} -#elif uECC_WORD_SIZE == 4 -static void vli_mmod_fast_secp256r1(uint32_t *result, uint32_t *product) { - uint32_t tmp[num_words_secp256r1]; - int carry; - - /* t */ - uECC_vli_set(result, product, num_words_secp256r1); - - /* s1 */ - tmp[0] = tmp[1] = tmp[2] = 0; - tmp[3] = product[11]; - tmp[4] = product[12]; - tmp[5] = product[13]; - tmp[6] = product[14]; - tmp[7] = product[15]; - carry = uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* s2 */ - tmp[3] = product[12]; - tmp[4] = product[13]; - tmp[5] = product[14]; - tmp[6] = product[15]; - tmp[7] = 0; - carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* s3 */ - tmp[0] = product[8]; - tmp[1] = product[9]; - tmp[2] = product[10]; - tmp[3] = tmp[4] = tmp[5] = 0; - tmp[6] = product[14]; - tmp[7] = product[15]; - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* s4 */ - tmp[0] = product[9]; - tmp[1] = product[10]; - tmp[2] = product[11]; - tmp[3] = product[13]; - tmp[4] = product[14]; - tmp[5] = product[15]; - tmp[6] = product[13]; - tmp[7] = product[8]; - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* d1 */ - tmp[0] = product[11]; - tmp[1] = product[12]; - tmp[2] = product[13]; - tmp[3] = tmp[4] = tmp[5] = 0; - tmp[6] = product[8]; - tmp[7] = product[10]; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - /* d2 */ - tmp[0] = product[12]; - tmp[1] = product[13]; - tmp[2] = product[14]; - tmp[3] = product[15]; - tmp[4] = tmp[5] = 0; - tmp[6] = product[9]; - tmp[7] = product[11]; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - /* d3 */ - tmp[0] = product[13]; - tmp[1] = product[14]; - tmp[2] = product[15]; - tmp[3] = product[8]; - tmp[4] = product[9]; - tmp[5] = product[10]; - tmp[6] = 0; - tmp[7] = product[12]; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - /* d4 */ - tmp[0] = product[14]; - tmp[1] = product[15]; - tmp[2] = 0; - tmp[3] = product[9]; - tmp[4] = product[10]; - tmp[5] = product[11]; - tmp[6] = 0; - tmp[7] = product[13]; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - if (carry < 0) { - do { - carry += uECC_vli_add(result, result, curve_secp256r1.p, num_words_secp256r1); - } while (carry < 0); - } else { - while (carry || uECC_vli_cmp_unsafe(curve_secp256r1.p, result, num_words_secp256r1) != 1) { - carry -= uECC_vli_sub(result, result, curve_secp256r1.p, num_words_secp256r1); - } - } -} -#else -static void vli_mmod_fast_secp256r1(uint64_t *result, uint64_t *product) { - uint64_t tmp[num_words_secp256r1]; - int carry; - - /* t */ - uECC_vli_set(result, product, num_words_secp256r1); - - /* s1 */ - tmp[0] = 0; - tmp[1] = product[5] & 0xffffffff00000000ull; - tmp[2] = product[6]; - tmp[3] = product[7]; - carry = (int)uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* s2 */ - tmp[1] = product[6] << 32; - tmp[2] = (product[6] >> 32) | (product[7] << 32); - tmp[3] = product[7] >> 32; - carry += uECC_vli_add(tmp, tmp, tmp, num_words_secp256r1); - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* s3 */ - tmp[0] = product[4]; - tmp[1] = product[5] & 0xffffffff; - tmp[2] = 0; - tmp[3] = product[7]; - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* s4 */ - tmp[0] = (product[4] >> 32) | (product[5] << 32); - tmp[1] = (product[5] >> 32) | (product[6] & 0xffffffff00000000ull); - tmp[2] = product[7]; - tmp[3] = (product[6] >> 32) | (product[4] << 32); - carry += uECC_vli_add(result, result, tmp, num_words_secp256r1); - - /* d1 */ - tmp[0] = (product[5] >> 32) | (product[6] << 32); - tmp[1] = (product[6] >> 32); - tmp[2] = 0; - tmp[3] = (product[4] & 0xffffffff) | (product[5] << 32); - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - /* d2 */ - tmp[0] = product[6]; - tmp[1] = product[7]; - tmp[2] = 0; - tmp[3] = (product[4] >> 32) | (product[5] & 0xffffffff00000000ull); - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - /* d3 */ - tmp[0] = (product[6] >> 32) | (product[7] << 32); - tmp[1] = (product[7] >> 32) | (product[4] << 32); - tmp[2] = (product[4] >> 32) | (product[5] << 32); - tmp[3] = (product[6] << 32); - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - /* d4 */ - tmp[0] = product[7]; - tmp[1] = product[4] & 0xffffffff00000000ull; - tmp[2] = product[5]; - tmp[3] = product[6] & 0xffffffff00000000ull; - carry -= uECC_vli_sub(result, result, tmp, num_words_secp256r1); - - if (carry < 0) { - do { - carry += uECC_vli_add(result, result, curve_secp256r1.p, num_words_secp256r1); - } while (carry < 0); - } else { - while (carry || uECC_vli_cmp_unsafe(curve_secp256r1.p, result, num_words_secp256r1) != 1) { - carry -= uECC_vli_sub(result, result, curve_secp256r1.p, num_words_secp256r1); - } - } -} -#endif /* uECC_WORD_SIZE */ -#endif /* (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp256r1) */ - -#endif /* uECC_SUPPORTS_secp256r1 */ - -#if uECC_SUPPORTS_secp256k1 - -static void double_jacobian_secp256k1(uECC_word_t * X1, - uECC_word_t * Y1, - uECC_word_t * Z1, - uECC_Curve curve); -static void x_side_secp256k1(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve); -#if (uECC_OPTIMIZATION_LEVEL > 0) -static void vli_mmod_fast_secp256k1(uECC_word_t *result, uECC_word_t *product); -#endif - -static const struct uECC_Curve_t curve_secp256k1 = { - num_words_secp256k1, - num_bytes_secp256k1, - 256, /* num_n_bits */ - { BYTES_TO_WORDS_8(2F, FC, FF, FF, FE, FF, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) }, - { BYTES_TO_WORDS_8(41, 41, 36, D0, 8C, 5E, D2, BF), - BYTES_TO_WORDS_8(3B, A0, 48, AF, E6, DC, AE, BA), - BYTES_TO_WORDS_8(FE, FF, FF, FF, FF, FF, FF, FF), - BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) }, - { BYTES_TO_WORDS_8(98, 17, F8, 16, 5B, 81, F2, 59), - BYTES_TO_WORDS_8(D9, 28, CE, 2D, DB, FC, 9B, 02), - BYTES_TO_WORDS_8(07, 0B, 87, CE, 95, 62, A0, 55), - BYTES_TO_WORDS_8(AC, BB, DC, F9, 7E, 66, BE, 79), - - BYTES_TO_WORDS_8(B8, D4, 10, FB, 8F, D0, 47, 9C), - BYTES_TO_WORDS_8(19, 54, 85, A6, 48, B4, 17, FD), - BYTES_TO_WORDS_8(A8, 08, 11, 0E, FC, FB, A4, 5D), - BYTES_TO_WORDS_8(65, C4, A3, 26, 77, DA, 3A, 48) }, - { BYTES_TO_WORDS_8(07, 00, 00, 00, 00, 00, 00, 00), - BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00), - BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00), - BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00) }, - &double_jacobian_secp256k1, -#if uECC_SUPPORT_COMPRESSED_POINT - &mod_sqrt_default, -#endif - &x_side_secp256k1, -#if (uECC_OPTIMIZATION_LEVEL > 0) - &vli_mmod_fast_secp256k1 -#endif -}; - -uECC_Curve uECC_secp256k1(void) { return &curve_secp256k1; } - - -/* Double in place */ -static void double_jacobian_secp256k1(uECC_word_t * X1, - uECC_word_t * Y1, - uECC_word_t * Z1, - uECC_Curve curve) { - /* t1 = X, t2 = Y, t3 = Z */ - uECC_word_t t4[num_words_secp256k1]; - uECC_word_t t5[num_words_secp256k1]; - - if (uECC_vli_isZero(Z1, num_words_secp256k1)) { - return; - } - - uECC_vli_modSquare_fast(t5, Y1, curve); /* t5 = y1^2 */ - uECC_vli_modMult_fast(t4, X1, t5, curve); /* t4 = x1*y1^2 = A */ - uECC_vli_modSquare_fast(X1, X1, curve); /* t1 = x1^2 */ - uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = y1^4 */ - uECC_vli_modMult_fast(Z1, Y1, Z1, curve); /* t3 = y1*z1 = z3 */ - - uECC_vli_modAdd(Y1, X1, X1, curve->p, num_words_secp256k1); /* t2 = 2*x1^2 */ - uECC_vli_modAdd(Y1, Y1, X1, curve->p, num_words_secp256k1); /* t2 = 3*x1^2 */ - if (uECC_vli_testBit(Y1, 0)) { - uECC_word_t carry = uECC_vli_add(Y1, Y1, curve->p, num_words_secp256k1); - uECC_vli_rshift1(Y1, num_words_secp256k1); - Y1[num_words_secp256k1 - 1] |= carry << (uECC_WORD_BITS - 1); - } else { - uECC_vli_rshift1(Y1, num_words_secp256k1); - } - /* t2 = 3/2*(x1^2) = B */ - - uECC_vli_modSquare_fast(X1, Y1, curve); /* t1 = B^2 */ - uECC_vli_modSub(X1, X1, t4, curve->p, num_words_secp256k1); /* t1 = B^2 - A */ - uECC_vli_modSub(X1, X1, t4, curve->p, num_words_secp256k1); /* t1 = B^2 - 2A = x3 */ - - uECC_vli_modSub(t4, t4, X1, curve->p, num_words_secp256k1); /* t4 = A - x3 */ - uECC_vli_modMult_fast(Y1, Y1, t4, curve); /* t2 = B * (A - x3) */ - uECC_vli_modSub(Y1, Y1, t5, curve->p, num_words_secp256k1); /* t2 = B * (A - x3) - y1^4 = y3 */ -} - -/* Computes result = x^3 + b. result must not overlap x. */ -static void x_side_secp256k1(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve) { - uECC_vli_modSquare_fast(result, x, curve); /* r = x^2 */ - uECC_vli_modMult_fast(result, result, x, curve); /* r = x^3 */ - uECC_vli_modAdd(result, result, curve->b, curve->p, num_words_secp256k1); /* r = x^3 + b */ -} - -#if (uECC_OPTIMIZATION_LEVEL > 0 && !asm_mmod_fast_secp256k1) -static void omega_mult_secp256k1(uECC_word_t *result, const uECC_word_t *right); -static void vli_mmod_fast_secp256k1(uECC_word_t *result, uECC_word_t *product) { - uECC_word_t tmp[2 * num_words_secp256k1]; - uECC_word_t carry; - - uECC_vli_clear(tmp, num_words_secp256k1); - uECC_vli_clear(tmp + num_words_secp256k1, num_words_secp256k1); - - omega_mult_secp256k1(tmp, product + num_words_secp256k1); /* (Rq, q) = q * c */ - - carry = uECC_vli_add(result, product, tmp, num_words_secp256k1); /* (C, r) = r + q */ - uECC_vli_clear(product, num_words_secp256k1); - omega_mult_secp256k1(product, tmp + num_words_secp256k1); /* Rq*c */ - carry += uECC_vli_add(result, result, product, num_words_secp256k1); /* (C1, r) = r + Rq*c */ - - while (carry > 0) { - --carry; - uECC_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1); - } - if (uECC_vli_cmp_unsafe(result, curve_secp256k1.p, num_words_secp256k1) > 0) { - uECC_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1); - } -} - -#if uECC_WORD_SIZE == 1 -static void omega_mult_secp256k1(uint8_t * result, const uint8_t * right) { - /* Multiply by (2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */ - uECC_word_t r0 = 0; - uECC_word_t r1 = 0; - uECC_word_t r2 = 0; - wordcount_t k; - - /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */ - muladd(0xD1, right[0], &r0, &r1, &r2); - result[0] = r0; - r0 = r1; - r1 = r2; - /* r2 is still 0 */ - - for (k = 1; k < num_words_secp256k1; ++k) { - muladd(0x03, right[k - 1], &r0, &r1, &r2); - muladd(0xD1, right[k], &r0, &r1, &r2); - result[k] = r0; - r0 = r1; - r1 = r2; - r2 = 0; - } - muladd(0x03, right[num_words_secp256k1 - 1], &r0, &r1, &r2); - result[num_words_secp256k1] = r0; - result[num_words_secp256k1 + 1] = r1; - /* add the 2^32 multiple */ - result[4 + num_words_secp256k1] = - uECC_vli_add(result + 4, result + 4, right, num_words_secp256k1); -} -#elif uECC_WORD_SIZE == 4 -static void omega_mult_secp256k1(uint32_t * result, const uint32_t * right) { - /* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */ - uint32_t carry = 0; - wordcount_t k; - - for (k = 0; k < num_words_secp256k1; ++k) { - uint64_t p = (uint64_t)0x3D1 * right[k] + carry; - result[k] = (uint32_t) p; - carry = p >> 32; - } - result[num_words_secp256k1] = carry; - /* add the 2^32 multiple */ - result[1 + num_words_secp256k1] = - uECC_vli_add(result + 1, result + 1, right, num_words_secp256k1); -} -#else -static void omega_mult_secp256k1(uint64_t * result, const uint64_t * right) { - uECC_word_t r0 = 0; - uECC_word_t r1 = 0; - uECC_word_t r2 = 0; - wordcount_t k; - - /* Multiply by (2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */ - for (k = 0; k < num_words_secp256k1; ++k) { - muladd(0x1000003D1ull, right[k], &r0, &r1, &r2); - result[k] = r0; - r0 = r1; - r1 = r2; - r2 = 0; - } - result[num_words_secp256k1] = r0; -} -#endif /* uECC_WORD_SIZE */ -#endif /* (uECC_OPTIMIZATION_LEVEL > 0 && && !asm_mmod_fast_secp256k1) */ - -#endif /* uECC_SUPPORTS_secp256k1 */ - -#endif /* _UECC_CURVE_SPECIFIC_H_ */ diff --git a/lib/micro-ecc/platform-specific.inc b/lib/micro-ecc/platform-specific.inc deleted file mode 100644 index 7e0373f5059..00000000000 --- a/lib/micro-ecc/platform-specific.inc +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ - -#ifndef _UECC_PLATFORM_SPECIFIC_H_ -#define _UECC_PLATFORM_SPECIFIC_H_ - -#include "types.h" - -#if (defined(_WIN32) || defined(_WIN64)) -/* Windows */ - -// use pragma syntax to prevent tweaking the linker script for getting CryptXYZ function -#pragma comment(lib, "crypt32.lib") -#pragma comment(lib, "advapi32.lib") - -#define WIN32_LEAN_AND_MEAN -#include -#include - -static int default_RNG(uint8_t *dest, unsigned size) { - HCRYPTPROV prov; - if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { - return 0; - } - - CryptGenRandom(prov, size, (BYTE *)dest); - CryptReleaseContext(prov, 0); - return 1; -} -#define default_RNG_defined 1 - -#elif defined(unix) || defined(__linux__) || defined(__unix__) || defined(__unix) || \ - (defined(__APPLE__) && defined(__MACH__)) || defined(uECC_POSIX) - -/* Some POSIX-like system with /dev/urandom or /dev/random. */ -#include -#include -#include - -#ifndef O_CLOEXEC - #define O_CLOEXEC 0 -#endif - -static int default_RNG(uint8_t *dest, unsigned size) { - int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); - if (fd == -1) { - fd = open("/dev/random", O_RDONLY | O_CLOEXEC); - if (fd == -1) { - return 0; - } - } - - char *ptr = (char *)dest; - size_t left = size; - while (left > 0) { - ssize_t bytes_read = read(fd, ptr, left); - if (bytes_read <= 0) { // read failed - close(fd); - return 0; - } - left -= bytes_read; - ptr += bytes_read; - } - - close(fd); - return 1; -} -#define default_RNG_defined 1 - -#elif defined(RIOT_VERSION) - -#include - -static int default_RNG(uint8_t *dest, unsigned size) { - random_bytes(dest, size); - return 1; -} -#define default_RNG_defined 1 - -#elif defined(NRF52_SERIES) - -#include "app_error.h" -#include "nrf_crypto_rng.h" - -static int default_RNG(uint8_t *dest, unsigned size) -{ - // make sure to call nrf_crypto_init and nrf_crypto_rng_init first - ret_code_t ret_code = nrf_crypto_rng_vector_generate(dest, size); - return (ret_code == NRF_SUCCESS) ? 1 : 0; -} -#define default_RNG_defined 1 - -#endif /* platform */ - -#endif /* _UECC_PLATFORM_SPECIFIC_H_ */ diff --git a/lib/micro-ecc/types.h b/lib/micro-ecc/types.h deleted file mode 100644 index 9ee81438fac..00000000000 --- a/lib/micro-ecc/types.h +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ - -#ifndef _UECC_TYPES_H_ -#define _UECC_TYPES_H_ - -#ifndef uECC_PLATFORM - #if __AVR__ - #define uECC_PLATFORM uECC_avr - #elif defined(__thumb2__) || defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */ - #define uECC_PLATFORM uECC_arm_thumb2 - #elif defined(__thumb__) - #define uECC_PLATFORM uECC_arm_thumb - #elif defined(__arm__) || defined(_M_ARM) - #define uECC_PLATFORM uECC_arm - #elif defined(__aarch64__) - #define uECC_PLATFORM uECC_arm64 - #elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__I86__) - #define uECC_PLATFORM uECC_x86 - #elif defined(__amd64__) || defined(_M_X64) - #define uECC_PLATFORM uECC_x86_64 - #else - #define uECC_PLATFORM uECC_arch_other - #endif -#endif - -#ifndef uECC_ARM_USE_UMAAL - #if (uECC_PLATFORM == uECC_arm) && (__ARM_ARCH >= 6) - #define uECC_ARM_USE_UMAAL 1 - #elif (uECC_PLATFORM == uECC_arm_thumb2) && (__ARM_ARCH >= 6) && !__ARM_ARCH_7M__ - #define uECC_ARM_USE_UMAAL 1 - #else - #define uECC_ARM_USE_UMAAL 0 - #endif -#endif - -#ifndef uECC_WORD_SIZE - #if uECC_PLATFORM == uECC_avr - #define uECC_WORD_SIZE 1 - #elif (uECC_PLATFORM == uECC_x86_64 || uECC_PLATFORM == uECC_arm64) - #define uECC_WORD_SIZE 8 - #else - #define uECC_WORD_SIZE 4 - #endif -#endif - -#if (uECC_WORD_SIZE != 1) && (uECC_WORD_SIZE != 4) && (uECC_WORD_SIZE != 8) - #error "Unsupported value for uECC_WORD_SIZE" -#endif - -#if ((uECC_PLATFORM == uECC_avr) && (uECC_WORD_SIZE != 1)) - #pragma message ("uECC_WORD_SIZE must be 1 for AVR") - #undef uECC_WORD_SIZE - #define uECC_WORD_SIZE 1 -#endif - -#if ((uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \ - uECC_PLATFORM == uECC_arm_thumb2) && \ - (uECC_WORD_SIZE != 4)) - #pragma message ("uECC_WORD_SIZE must be 4 for ARM") - #undef uECC_WORD_SIZE - #define uECC_WORD_SIZE 4 -#endif - -#if defined(__SIZEOF_INT128__) || ((__clang_major__ * 100 + __clang_minor__) >= 302) - #define SUPPORTS_INT128 1 -#else - #define SUPPORTS_INT128 0 -#endif - -typedef int8_t wordcount_t; -typedef int16_t bitcount_t; -typedef int8_t cmpresult_t; - -#if (uECC_WORD_SIZE == 1) - -typedef uint8_t uECC_word_t; -typedef uint16_t uECC_dword_t; - -#define HIGH_BIT_SET 0x80 -#define uECC_WORD_BITS 8 -#define uECC_WORD_BITS_SHIFT 3 -#define uECC_WORD_BITS_MASK 0x07 - -#elif (uECC_WORD_SIZE == 4) - -typedef uint32_t uECC_word_t; -typedef uint64_t uECC_dword_t; - -#define HIGH_BIT_SET 0x80000000 -#define uECC_WORD_BITS 32 -#define uECC_WORD_BITS_SHIFT 5 -#define uECC_WORD_BITS_MASK 0x01F - -#elif (uECC_WORD_SIZE == 8) - -typedef uint64_t uECC_word_t; -#if SUPPORTS_INT128 -typedef unsigned __int128 uECC_dword_t; -#endif - -#define HIGH_BIT_SET 0x8000000000000000ull -#define uECC_WORD_BITS 64 -#define uECC_WORD_BITS_SHIFT 6 -#define uECC_WORD_BITS_MASK 0x03F - -#endif /* uECC_WORD_SIZE */ - -#endif /* _UECC_TYPES_H_ */ diff --git a/lib/micro-ecc/uECC.c b/lib/micro-ecc/uECC.c deleted file mode 100644 index a3d502cf21b..00000000000 --- a/lib/micro-ecc/uECC.c +++ /dev/null @@ -1,1669 +0,0 @@ -/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */ - -#include "uECC.h" -#include "uECC_vli.h" - -#ifndef uECC_RNG_MAX_TRIES - #define uECC_RNG_MAX_TRIES 64 -#endif - -#if uECC_ENABLE_VLI_API - #define uECC_VLI_API -#else - #define uECC_VLI_API static -#endif - -#if (uECC_PLATFORM == uECC_avr) || \ - (uECC_PLATFORM == uECC_arm) || \ - (uECC_PLATFORM == uECC_arm_thumb) || \ - (uECC_PLATFORM == uECC_arm_thumb2) - #define CONCATX(a, ...) a ## __VA_ARGS__ - #define CONCAT(a, ...) CONCATX(a, __VA_ARGS__) - - #define STRX(a) #a - #define STR(a) STRX(a) - - #define EVAL(...) EVAL1(EVAL1(EVAL1(EVAL1(__VA_ARGS__)))) - #define EVAL1(...) EVAL2(EVAL2(EVAL2(EVAL2(__VA_ARGS__)))) - #define EVAL2(...) EVAL3(EVAL3(EVAL3(EVAL3(__VA_ARGS__)))) - #define EVAL3(...) EVAL4(EVAL4(EVAL4(EVAL4(__VA_ARGS__)))) - #define EVAL4(...) __VA_ARGS__ - - #define DEC_1 0 - #define DEC_2 1 - #define DEC_3 2 - #define DEC_4 3 - #define DEC_5 4 - #define DEC_6 5 - #define DEC_7 6 - #define DEC_8 7 - #define DEC_9 8 - #define DEC_10 9 - #define DEC_11 10 - #define DEC_12 11 - #define DEC_13 12 - #define DEC_14 13 - #define DEC_15 14 - #define DEC_16 15 - #define DEC_17 16 - #define DEC_18 17 - #define DEC_19 18 - #define DEC_20 19 - #define DEC_21 20 - #define DEC_22 21 - #define DEC_23 22 - #define DEC_24 23 - #define DEC_25 24 - #define DEC_26 25 - #define DEC_27 26 - #define DEC_28 27 - #define DEC_29 28 - #define DEC_30 29 - #define DEC_31 30 - #define DEC_32 31 - - #define DEC(N) CONCAT(DEC_, N) - - #define SECOND_ARG(_, val, ...) val - #define SOME_CHECK_0 ~, 0 - #define GET_SECOND_ARG(...) SECOND_ARG(__VA_ARGS__, SOME,) - #define SOME_OR_0(N) GET_SECOND_ARG(CONCAT(SOME_CHECK_, N)) - - #define EMPTY(...) - #define DEFER(...) __VA_ARGS__ EMPTY() - - #define REPEAT_NAME_0() REPEAT_0 - #define REPEAT_NAME_SOME() REPEAT_SOME - #define REPEAT_0(...) - #define REPEAT_SOME(N, stuff) DEFER(CONCAT(REPEAT_NAME_, SOME_OR_0(DEC(N))))()(DEC(N), stuff) stuff - #define REPEAT(N, stuff) EVAL(REPEAT_SOME(N, stuff)) - - #define REPEATM_NAME_0() REPEATM_0 - #define REPEATM_NAME_SOME() REPEATM_SOME - #define REPEATM_0(...) - #define REPEATM_SOME(N, macro) macro(N) \ - DEFER(CONCAT(REPEATM_NAME_, SOME_OR_0(DEC(N))))()(DEC(N), macro) - #define REPEATM(N, macro) EVAL(REPEATM_SOME(N, macro)) -#endif - -#include "platform-specific.inc" - -#if (uECC_WORD_SIZE == 1) - #if uECC_SUPPORTS_secp160r1 - #define uECC_MAX_WORDS 21 /* Due to the size of curve_n. */ - #endif - #if uECC_SUPPORTS_secp192r1 - #undef uECC_MAX_WORDS - #define uECC_MAX_WORDS 24 - #endif - #if uECC_SUPPORTS_secp224r1 - #undef uECC_MAX_WORDS - #define uECC_MAX_WORDS 28 - #endif - #if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1) - #undef uECC_MAX_WORDS - #define uECC_MAX_WORDS 32 - #endif -#elif (uECC_WORD_SIZE == 4) - #if uECC_SUPPORTS_secp160r1 - #define uECC_MAX_WORDS 6 /* Due to the size of curve_n. */ - #endif - #if uECC_SUPPORTS_secp192r1 - #undef uECC_MAX_WORDS - #define uECC_MAX_WORDS 6 - #endif - #if uECC_SUPPORTS_secp224r1 - #undef uECC_MAX_WORDS - #define uECC_MAX_WORDS 7 - #endif - #if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1) - #undef uECC_MAX_WORDS - #define uECC_MAX_WORDS 8 - #endif -#elif (uECC_WORD_SIZE == 8) - #if uECC_SUPPORTS_secp160r1 - #define uECC_MAX_WORDS 3 - #endif - #if uECC_SUPPORTS_secp192r1 - #undef uECC_MAX_WORDS - #define uECC_MAX_WORDS 3 - #endif - #if uECC_SUPPORTS_secp224r1 - #undef uECC_MAX_WORDS - #define uECC_MAX_WORDS 4 - #endif - #if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1) - #undef uECC_MAX_WORDS - #define uECC_MAX_WORDS 4 - #endif -#endif /* uECC_WORD_SIZE */ - -#define BITS_TO_WORDS(num_bits) ((num_bits + ((uECC_WORD_SIZE * 8) - 1)) / (uECC_WORD_SIZE * 8)) -#define BITS_TO_BYTES(num_bits) ((num_bits + 7) / 8) - -struct uECC_Curve_t { - wordcount_t num_words; - wordcount_t num_bytes; - bitcount_t num_n_bits; - uECC_word_t p[uECC_MAX_WORDS]; - uECC_word_t n[uECC_MAX_WORDS]; - uECC_word_t G[uECC_MAX_WORDS * 2]; - uECC_word_t b[uECC_MAX_WORDS]; - void (*double_jacobian)(uECC_word_t * X1, - uECC_word_t * Y1, - uECC_word_t * Z1, - uECC_Curve curve); -#if uECC_SUPPORT_COMPRESSED_POINT - void (*mod_sqrt)(uECC_word_t *a, uECC_Curve curve); -#endif - void (*x_side)(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve); -#if (uECC_OPTIMIZATION_LEVEL > 0) - void (*mmod_fast)(uECC_word_t *result, uECC_word_t *product); -#endif -}; - -#if uECC_VLI_NATIVE_LITTLE_ENDIAN -static void bcopy(uint8_t *dst, - const uint8_t *src, - unsigned num_bytes) { - while (0 != num_bytes) { - num_bytes--; - dst[num_bytes] = src[num_bytes]; - } -} -#endif - -static cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words); - -#if (uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \ - uECC_PLATFORM == uECC_arm_thumb2) - #include "asm_arm.inc" -#endif - -#if (uECC_PLATFORM == uECC_avr) - #include "asm_avr.inc" -#endif - -#if default_RNG_defined -static uECC_RNG_Function g_rng_function = &default_RNG; -#else -static uECC_RNG_Function g_rng_function = 0; -#endif - -void uECC_set_rng(uECC_RNG_Function rng_function) { - g_rng_function = rng_function; -} - -uECC_RNG_Function uECC_get_rng(void) { - return g_rng_function; -} - -int uECC_curve_private_key_size(uECC_Curve curve) { - return BITS_TO_BYTES(curve->num_n_bits); -} - -int uECC_curve_public_key_size(uECC_Curve curve) { - return 2 * curve->num_bytes; -} - -#if !asm_clear -uECC_VLI_API void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words) { - wordcount_t i; - for (i = 0; i < num_words; ++i) { - vli[i] = 0; - } -} -#endif /* !asm_clear */ - -/* Constant-time comparison to zero - secure way to compare long integers */ -/* Returns 1 if vli == 0, 0 otherwise. */ -uECC_VLI_API uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words) { - uECC_word_t bits = 0; - wordcount_t i; - for (i = 0; i < num_words; ++i) { - bits |= vli[i]; - } - return (bits == 0); -} - -/* Returns nonzero if bit 'bit' of vli is set. */ -uECC_VLI_API uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit) { - return (vli[bit >> uECC_WORD_BITS_SHIFT] & ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK))); -} - -/* Counts the number of words in vli. */ -static wordcount_t vli_numDigits(const uECC_word_t *vli, const wordcount_t max_words) { - wordcount_t i; - /* Search from the end until we find a non-zero digit. - We do it in reverse because we expect that most digits will be nonzero. */ - for (i = max_words - 1; i >= 0 && vli[i] == 0; --i) { - } - - return (i + 1); -} - -/* Counts the number of bits required to represent vli. */ -uECC_VLI_API bitcount_t uECC_vli_numBits(const uECC_word_t *vli, const wordcount_t max_words) { - uECC_word_t i; - uECC_word_t digit; - - wordcount_t num_digits = vli_numDigits(vli, max_words); - if (num_digits == 0) { - return 0; - } - - digit = vli[num_digits - 1]; - for (i = 0; digit; ++i) { - digit >>= 1; - } - - return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i); -} - -/* Sets dest = src. */ -#if !asm_set -uECC_VLI_API void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, wordcount_t num_words) { - wordcount_t i; - for (i = 0; i < num_words; ++i) { - dest[i] = src[i]; - } -} -#endif /* !asm_set */ - -/* Returns sign of left - right. */ -static cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { - wordcount_t i; - for (i = num_words - 1; i >= 0; --i) { - if (left[i] > right[i]) { - return 1; - } else if (left[i] < right[i]) { - return -1; - } - } - return 0; -} - -/* Constant-time comparison function - secure way to compare long integers */ -/* Returns one if left == right, zero otherwise. */ -uECC_VLI_API uECC_word_t uECC_vli_equal(const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { - uECC_word_t diff = 0; - wordcount_t i; - for (i = num_words - 1; i >= 0; --i) { - diff |= (left[i] ^ right[i]); - } - return (diff == 0); -} - -uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words); - -/* Returns sign of left - right, in constant time. */ -uECC_VLI_API cmpresult_t uECC_vli_cmp(const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { - uECC_word_t tmp[uECC_MAX_WORDS]; - uECC_word_t neg = !!uECC_vli_sub(tmp, left, right, num_words); - uECC_word_t equal = uECC_vli_isZero(tmp, num_words); - return (!equal - 2 * neg); -} - -/* Computes vli = vli >> 1. */ -#if !asm_rshift1 -uECC_VLI_API void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words) { - uECC_word_t *end = vli; - uECC_word_t carry = 0; - - vli += num_words; - while (vli-- > end) { - uECC_word_t temp = *vli; - *vli = (temp >> 1) | carry; - carry = temp << (uECC_WORD_BITS - 1); - } -} -#endif /* !asm_rshift1 */ - -/* Computes result = left + right, returning carry. Can modify in place. */ -#if !asm_add -uECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { - uECC_word_t carry = 0; - wordcount_t i; - for (i = 0; i < num_words; ++i) { - uECC_word_t sum = left[i] + right[i] + carry; - if (sum != left[i]) { - carry = (sum < left[i]); - } - result[i] = sum; - } - return carry; -} -#endif /* !asm_add */ - -/* Computes result = left - right, returning borrow. Can modify in place. */ -#if !asm_sub -uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { - uECC_word_t borrow = 0; - wordcount_t i; - for (i = 0; i < num_words; ++i) { - uECC_word_t diff = left[i] - right[i] - borrow; - if (diff != left[i]) { - borrow = (diff > left[i]); - } - result[i] = diff; - } - return borrow; -} -#endif /* !asm_sub */ - -#if !asm_mult || (uECC_SQUARE_FUNC && !asm_square) || \ - (uECC_SUPPORTS_secp256k1 && (uECC_OPTIMIZATION_LEVEL > 0) && \ - ((uECC_WORD_SIZE == 1) || (uECC_WORD_SIZE == 8))) -static void muladd(uECC_word_t a, - uECC_word_t b, - uECC_word_t *r0, - uECC_word_t *r1, - uECC_word_t *r2) { -#if uECC_WORD_SIZE == 8 && !SUPPORTS_INT128 - uint64_t a0 = a & 0xffffffffull; - uint64_t a1 = a >> 32; - uint64_t b0 = b & 0xffffffffull; - uint64_t b1 = b >> 32; - - uint64_t i0 = a0 * b0; - uint64_t i1 = a0 * b1; - uint64_t i2 = a1 * b0; - uint64_t i3 = a1 * b1; - - uint64_t p0, p1; - - i2 += (i0 >> 32); - i2 += i1; - if (i2 < i1) { /* overflow */ - i3 += 0x100000000ull; - } - - p0 = (i0 & 0xffffffffull) | (i2 << 32); - p1 = i3 + (i2 >> 32); - - *r0 += p0; - *r1 += (p1 + (*r0 < p0)); - *r2 += ((*r1 < p1) || (*r1 == p1 && *r0 < p0)); -#else - uECC_dword_t p = (uECC_dword_t)a * b; - uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0; - r01 += p; - *r2 += (r01 < p); - *r1 = r01 >> uECC_WORD_BITS; - *r0 = (uECC_word_t)r01; -#endif -} -#endif /* muladd needed */ - -#if !asm_mult -uECC_VLI_API void uECC_vli_mult(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words) { - uECC_word_t r0 = 0; - uECC_word_t r1 = 0; - uECC_word_t r2 = 0; - wordcount_t i, k; - - /* Compute each digit of result in sequence, maintaining the carries. */ - for (k = 0; k < num_words; ++k) { - for (i = 0; i <= k; ++i) { - muladd(left[i], right[k - i], &r0, &r1, &r2); - } - result[k] = r0; - r0 = r1; - r1 = r2; - r2 = 0; - } - for (k = num_words; k < num_words * 2 - 1; ++k) { - for (i = (k + 1) - num_words; i < num_words; ++i) { - muladd(left[i], right[k - i], &r0, &r1, &r2); - } - result[k] = r0; - r0 = r1; - r1 = r2; - r2 = 0; - } - result[num_words * 2 - 1] = r0; -} -#endif /* !asm_mult */ - -#if uECC_SQUARE_FUNC - -#if !asm_square -static void mul2add(uECC_word_t a, - uECC_word_t b, - uECC_word_t *r0, - uECC_word_t *r1, - uECC_word_t *r2) { -#if uECC_WORD_SIZE == 8 && !SUPPORTS_INT128 - uint64_t a0 = a & 0xffffffffull; - uint64_t a1 = a >> 32; - uint64_t b0 = b & 0xffffffffull; - uint64_t b1 = b >> 32; - - uint64_t i0 = a0 * b0; - uint64_t i1 = a0 * b1; - uint64_t i2 = a1 * b0; - uint64_t i3 = a1 * b1; - - uint64_t p0, p1; - - i2 += (i0 >> 32); - i2 += i1; - if (i2 < i1) - { /* overflow */ - i3 += 0x100000000ull; - } - - p0 = (i0 & 0xffffffffull) | (i2 << 32); - p1 = i3 + (i2 >> 32); - - *r2 += (p1 >> 63); - p1 = (p1 << 1) | (p0 >> 63); - p0 <<= 1; - - *r0 += p0; - *r1 += (p1 + (*r0 < p0)); - *r2 += ((*r1 < p1) || (*r1 == p1 && *r0 < p0)); -#else - uECC_dword_t p = (uECC_dword_t)a * b; - uECC_dword_t r01 = ((uECC_dword_t)(*r1) << uECC_WORD_BITS) | *r0; - *r2 += (p >> (uECC_WORD_BITS * 2 - 1)); - p *= 2; - r01 += p; - *r2 += (r01 < p); - *r1 = r01 >> uECC_WORD_BITS; - *r0 = (uECC_word_t)r01; -#endif -} - -uECC_VLI_API void uECC_vli_square(uECC_word_t *result, - const uECC_word_t *left, - wordcount_t num_words) { - uECC_word_t r0 = 0; - uECC_word_t r1 = 0; - uECC_word_t r2 = 0; - - wordcount_t i, k; - - for (k = 0; k < num_words * 2 - 1; ++k) { - uECC_word_t min = (k < num_words ? 0 : (k + 1) - num_words); - for (i = min; i <= k && i <= k - i; ++i) { - if (i < k-i) { - mul2add(left[i], left[k - i], &r0, &r1, &r2); - } else { - muladd(left[i], left[k - i], &r0, &r1, &r2); - } - } - result[k] = r0; - r0 = r1; - r1 = r2; - r2 = 0; - } - - result[num_words * 2 - 1] = r0; -} -#endif /* !asm_square */ - -#else /* uECC_SQUARE_FUNC */ - -#if uECC_ENABLE_VLI_API -uECC_VLI_API void uECC_vli_square(uECC_word_t *result, - const uECC_word_t *left, - wordcount_t num_words) { - uECC_vli_mult(result, left, left, num_words); -} -#endif /* uECC_ENABLE_VLI_API */ - -#endif /* uECC_SQUARE_FUNC */ - -/* Computes result = (left + right) % mod. - Assumes that left < mod and right < mod, and that result does not overlap mod. */ -uECC_VLI_API void uECC_vli_modAdd(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - const uECC_word_t *mod, - wordcount_t num_words) { - uECC_word_t carry = uECC_vli_add(result, left, right, num_words); - if (carry || uECC_vli_cmp_unsafe(mod, result, num_words) != 1) { - /* result > mod (result = mod + remainder), so subtract mod to get remainder. */ - uECC_vli_sub(result, result, mod, num_words); - } -} - -/* Computes result = (left - right) % mod. - Assumes that left < mod and right < mod, and that result does not overlap mod. */ -uECC_VLI_API void uECC_vli_modSub(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - const uECC_word_t *mod, - wordcount_t num_words) { - uECC_word_t l_borrow = uECC_vli_sub(result, left, right, num_words); - if (l_borrow) { - /* In this case, result == -diff == (max int) - diff. Since -x % d == d - x, - we can get the correct result from result + mod (with overflow). */ - uECC_vli_add(result, result, mod, num_words); - } -} - -/* Computes result = product % mod, where product is 2N words long. */ -/* Currently only designed to work for curve_p or curve_n. */ -uECC_VLI_API void uECC_vli_mmod(uECC_word_t *result, - uECC_word_t *product, - const uECC_word_t *mod, - wordcount_t num_words) { - uECC_word_t mod_multiple[2 * uECC_MAX_WORDS]; - uECC_word_t tmp[2 * uECC_MAX_WORDS]; - uECC_word_t *v[2] = {tmp, product}; - uECC_word_t index; - - /* Shift mod so its highest set bit is at the maximum position. */ - bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) - uECC_vli_numBits(mod, num_words); - wordcount_t word_shift = shift / uECC_WORD_BITS; - wordcount_t bit_shift = shift % uECC_WORD_BITS; - uECC_word_t carry = 0; - uECC_vli_clear(mod_multiple, word_shift); - if (bit_shift > 0) { - for(index = 0; index < (uECC_word_t)num_words; ++index) { - mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry; - carry = mod[index] >> (uECC_WORD_BITS - bit_shift); - } - } else { - uECC_vli_set(mod_multiple + word_shift, mod, num_words); - } - - for (index = 1; shift >= 0; --shift) { - uECC_word_t borrow = 0; - wordcount_t i; - for (i = 0; i < num_words * 2; ++i) { - uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow; - if (diff != v[index][i]) { - borrow = (diff > v[index][i]); - } - v[1 - index][i] = diff; - } - index = !(index ^ borrow); /* Swap the index if there was no borrow */ - uECC_vli_rshift1(mod_multiple, num_words); - mod_multiple[num_words - 1] |= mod_multiple[num_words] << (uECC_WORD_BITS - 1); - uECC_vli_rshift1(mod_multiple + num_words, num_words); - } - uECC_vli_set(result, v[index], num_words); -} - -/* Computes result = (left * right) % mod. */ -uECC_VLI_API void uECC_vli_modMult(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - const uECC_word_t *mod, - wordcount_t num_words) { - uECC_word_t product[2 * uECC_MAX_WORDS]; - uECC_vli_mult(product, left, right, num_words); - uECC_vli_mmod(result, product, mod, num_words); -} - -uECC_VLI_API void uECC_vli_modMult_fast(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - uECC_Curve curve) { - uECC_word_t product[2 * uECC_MAX_WORDS]; - uECC_vli_mult(product, left, right, curve->num_words); -#if (uECC_OPTIMIZATION_LEVEL > 0) - curve->mmod_fast(result, product); -#else - uECC_vli_mmod(result, product, curve->p, curve->num_words); -#endif -} - -#if uECC_SQUARE_FUNC - -#if uECC_ENABLE_VLI_API -/* Computes result = left^2 % mod. */ -uECC_VLI_API void uECC_vli_modSquare(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *mod, - wordcount_t num_words) { - uECC_word_t product[2 * uECC_MAX_WORDS]; - uECC_vli_square(product, left, num_words); - uECC_vli_mmod(result, product, mod, num_words); -} -#endif /* uECC_ENABLE_VLI_API */ - -uECC_VLI_API void uECC_vli_modSquare_fast(uECC_word_t *result, - const uECC_word_t *left, - uECC_Curve curve) { - uECC_word_t product[2 * uECC_MAX_WORDS]; - uECC_vli_square(product, left, curve->num_words); -#if (uECC_OPTIMIZATION_LEVEL > 0) - curve->mmod_fast(result, product); -#else - uECC_vli_mmod(result, product, curve->p, curve->num_words); -#endif -} - -#else /* uECC_SQUARE_FUNC */ - -#if uECC_ENABLE_VLI_API -uECC_VLI_API void uECC_vli_modSquare(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *mod, - wordcount_t num_words) { - uECC_vli_modMult(result, left, left, mod, num_words); -} -#endif /* uECC_ENABLE_VLI_API */ - -uECC_VLI_API void uECC_vli_modSquare_fast(uECC_word_t *result, - const uECC_word_t *left, - uECC_Curve curve) { - uECC_vli_modMult_fast(result, left, left, curve); -} - -#endif /* uECC_SQUARE_FUNC */ - -#define EVEN(vli) (!(vli[0] & 1)) -static void vli_modInv_update(uECC_word_t *uv, - const uECC_word_t *mod, - wordcount_t num_words) { - uECC_word_t carry = 0; - if (!EVEN(uv)) { - carry = uECC_vli_add(uv, uv, mod, num_words); - } - uECC_vli_rshift1(uv, num_words); - if (carry) { - uv[num_words - 1] |= HIGH_BIT_SET; - } -} - -/* Computes result = (1 / input) % mod. All VLIs are the same size. - See "From Euclid's GCD to Montgomery Multiplication to the Great Divide" */ -uECC_VLI_API void uECC_vli_modInv(uECC_word_t *result, - const uECC_word_t *input, - const uECC_word_t *mod, - wordcount_t num_words) { - uECC_word_t a[uECC_MAX_WORDS], b[uECC_MAX_WORDS], u[uECC_MAX_WORDS], v[uECC_MAX_WORDS]; - cmpresult_t cmpResult; - - if (uECC_vli_isZero(input, num_words)) { - uECC_vli_clear(result, num_words); - return; - } - - uECC_vli_set(a, input, num_words); - uECC_vli_set(b, mod, num_words); - uECC_vli_clear(u, num_words); - u[0] = 1; - uECC_vli_clear(v, num_words); - while ((cmpResult = uECC_vli_cmp_unsafe(a, b, num_words)) != 0) { - if (EVEN(a)) { - uECC_vli_rshift1(a, num_words); - vli_modInv_update(u, mod, num_words); - } else if (EVEN(b)) { - uECC_vli_rshift1(b, num_words); - vli_modInv_update(v, mod, num_words); - } else if (cmpResult > 0) { - uECC_vli_sub(a, a, b, num_words); - uECC_vli_rshift1(a, num_words); - if (uECC_vli_cmp_unsafe(u, v, num_words) < 0) { - uECC_vli_add(u, u, mod, num_words); - } - uECC_vli_sub(u, u, v, num_words); - vli_modInv_update(u, mod, num_words); - } else { - uECC_vli_sub(b, b, a, num_words); - uECC_vli_rshift1(b, num_words); - if (uECC_vli_cmp_unsafe(v, u, num_words) < 0) { - uECC_vli_add(v, v, mod, num_words); - } - uECC_vli_sub(v, v, u, num_words); - vli_modInv_update(v, mod, num_words); - } - } - uECC_vli_set(result, u, num_words); -} - -/* ------ Point operations ------ */ - -#include "curve-specific.inc" - -/* Returns 1 if 'point' is the point at infinity, 0 otherwise. */ -#define EccPoint_isZero(point, curve) uECC_vli_isZero((point), (curve)->num_words * 2) - -/* Point multiplication algorithm using Montgomery's ladder with co-Z coordinates. -From http://eprint.iacr.org/2011/338.pdf -*/ - -/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */ -static void apply_z(uECC_word_t * X1, - uECC_word_t * Y1, - const uECC_word_t * const Z, - uECC_Curve curve) { - uECC_word_t t1[uECC_MAX_WORDS]; - - uECC_vli_modSquare_fast(t1, Z, curve); /* z^2 */ - uECC_vli_modMult_fast(X1, X1, t1, curve); /* x1 * z^2 */ - uECC_vli_modMult_fast(t1, t1, Z, curve); /* z^3 */ - uECC_vli_modMult_fast(Y1, Y1, t1, curve); /* y1 * z^3 */ -} - -/* P = (x1, y1) => 2P, (x2, y2) => P' */ -static void XYcZ_initial_double(uECC_word_t * X1, - uECC_word_t * Y1, - uECC_word_t * X2, - uECC_word_t * Y2, - const uECC_word_t * const initial_Z, - uECC_Curve curve) { - uECC_word_t z[uECC_MAX_WORDS]; - wordcount_t num_words = curve->num_words; - if (initial_Z) { - uECC_vli_set(z, initial_Z, num_words); - } else { - uECC_vli_clear(z, num_words); - z[0] = 1; - } - - uECC_vli_set(X2, X1, num_words); - uECC_vli_set(Y2, Y1, num_words); - - apply_z(X1, Y1, z, curve); - curve->double_jacobian(X1, Y1, z, curve); - apply_z(X2, Y2, z, curve); -} - -/* Input P = (x1, y1, Z), Q = (x2, y2, Z) - Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3) - or P => P', Q => P + Q -*/ -static void XYcZ_add(uECC_word_t * X1, - uECC_word_t * Y1, - uECC_word_t * X2, - uECC_word_t * Y2, - uECC_Curve curve) { - /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ - uECC_word_t t5[uECC_MAX_WORDS]; - wordcount_t num_words = curve->num_words; - - uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */ - uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */ - uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */ - uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */ - uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */ - uECC_vli_modSquare_fast(t5, Y2, curve); /* t5 = (y2 - y1)^2 = D */ - - uECC_vli_modSub(t5, t5, X1, curve->p, num_words); /* t5 = D - B */ - uECC_vli_modSub(t5, t5, X2, curve->p, num_words); /* t5 = D - B - C = x3 */ - uECC_vli_modSub(X2, X2, X1, curve->p, num_words); /* t3 = C - B */ - uECC_vli_modMult_fast(Y1, Y1, X2, curve); /* t2 = y1*(C - B) */ - uECC_vli_modSub(X2, X1, t5, curve->p, num_words); /* t3 = B - x3 */ - uECC_vli_modMult_fast(Y2, Y2, X2, curve); /* t4 = (y2 - y1)*(B - x3) */ - uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y3 */ - - uECC_vli_set(X2, t5, num_words); -} - -/* Input P = (x1, y1, Z), Q = (x2, y2, Z) - Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3) - or P => P - Q, Q => P + Q -*/ -static void XYcZ_addC(uECC_word_t * X1, - uECC_word_t * Y1, - uECC_word_t * X2, - uECC_word_t * Y2, - uECC_Curve curve) { - /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ - uECC_word_t t5[uECC_MAX_WORDS]; - uECC_word_t t6[uECC_MAX_WORDS]; - uECC_word_t t7[uECC_MAX_WORDS]; - wordcount_t num_words = curve->num_words; - - uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */ - uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */ - uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */ - uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */ - uECC_vli_modAdd(t5, Y2, Y1, curve->p, num_words); /* t5 = y2 + y1 */ - uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */ - - uECC_vli_modSub(t6, X2, X1, curve->p, num_words); /* t6 = C - B */ - uECC_vli_modMult_fast(Y1, Y1, t6, curve); /* t2 = y1 * (C - B) = E */ - uECC_vli_modAdd(t6, X1, X2, curve->p, num_words); /* t6 = B + C */ - uECC_vli_modSquare_fast(X2, Y2, curve); /* t3 = (y2 - y1)^2 = D */ - uECC_vli_modSub(X2, X2, t6, curve->p, num_words); /* t3 = D - (B + C) = x3 */ - - uECC_vli_modSub(t7, X1, X2, curve->p, num_words); /* t7 = B - x3 */ - uECC_vli_modMult_fast(Y2, Y2, t7, curve); /* t4 = (y2 - y1)*(B - x3) */ - uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = (y2 - y1)*(B - x3) - E = y3 */ - - uECC_vli_modSquare_fast(t7, t5, curve); /* t7 = (y2 + y1)^2 = F */ - uECC_vli_modSub(t7, t7, t6, curve->p, num_words); /* t7 = F - (B + C) = x3' */ - uECC_vli_modSub(t6, t7, X1, curve->p, num_words); /* t6 = x3' - B */ - uECC_vli_modMult_fast(t6, t6, t5, curve); /* t6 = (y2+y1)*(x3' - B) */ - uECC_vli_modSub(Y1, t6, Y1, curve->p, num_words); /* t2 = (y2+y1)*(x3' - B) - E = y3' */ - - uECC_vli_set(X1, t7, num_words); -} - -/* result may overlap point. */ -static void EccPoint_mult(uECC_word_t * result, - const uECC_word_t * point, - const uECC_word_t * scalar, - const uECC_word_t * initial_Z, - bitcount_t num_bits, - uECC_Curve curve) { - /* R0 and R1 */ - uECC_word_t Rx[2][uECC_MAX_WORDS]; - uECC_word_t Ry[2][uECC_MAX_WORDS]; - uECC_word_t z[uECC_MAX_WORDS]; - bitcount_t i; - uECC_word_t nb; - wordcount_t num_words = curve->num_words; - - uECC_vli_set(Rx[1], point, num_words); - uECC_vli_set(Ry[1], point + num_words, num_words); - - XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], initial_Z, curve); - - for (i = num_bits - 2; i > 0; --i) { - nb = !uECC_vli_testBit(scalar, i); - XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve); - XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve); - } - - nb = !uECC_vli_testBit(scalar, 0); - XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb], curve); - - /* Find final 1/Z value. */ - uECC_vli_modSub(z, Rx[1], Rx[0], curve->p, num_words); /* X1 - X0 */ - uECC_vli_modMult_fast(z, z, Ry[1 - nb], curve); /* Yb * (X1 - X0) */ - uECC_vli_modMult_fast(z, z, point, curve); /* xP * Yb * (X1 - X0) */ - uECC_vli_modInv(z, z, curve->p, num_words); /* 1 / (xP * Yb * (X1 - X0)) */ - /* yP / (xP * Yb * (X1 - X0)) */ - uECC_vli_modMult_fast(z, z, point + num_words, curve); - uECC_vli_modMult_fast(z, z, Rx[1 - nb], curve); /* Xb * yP / (xP * Yb * (X1 - X0)) */ - /* End 1/Z calculation */ - - XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb], curve); - apply_z(Rx[0], Ry[0], z, curve); - - uECC_vli_set(result, Rx[0], num_words); - uECC_vli_set(result + num_words, Ry[0], num_words); -} - -static uECC_word_t regularize_k(const uECC_word_t * const k, - uECC_word_t *k0, - uECC_word_t *k1, - uECC_Curve curve) { - wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); - bitcount_t num_n_bits = curve->num_n_bits; - uECC_word_t carry = uECC_vli_add(k0, k, curve->n, num_n_words) || - (num_n_bits < ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8) && - uECC_vli_testBit(k0, num_n_bits)); - uECC_vli_add(k1, k0, curve->n, num_n_words); - return carry; -} - -/* Generates a random integer in the range 0 < random < top. - Both random and top have num_words words. */ -uECC_VLI_API int uECC_generate_random_int(uECC_word_t *random, - const uECC_word_t *top, - wordcount_t num_words) { - uECC_word_t mask = (uECC_word_t)-1; - uECC_word_t tries; - bitcount_t num_bits = uECC_vli_numBits(top, num_words); - - if (!g_rng_function) { - return 0; - } - - for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { - if (!g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) { - return 0; - } - random[num_words - 1] &= mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits)); - if (!uECC_vli_isZero(random, num_words) && - uECC_vli_cmp(top, random, num_words) == 1) { - return 1; - } - } - return 0; -} - -static uECC_word_t EccPoint_compute_public_key(uECC_word_t *result, - uECC_word_t *private_key, - uECC_Curve curve) { - uECC_word_t tmp1[uECC_MAX_WORDS]; - uECC_word_t tmp2[uECC_MAX_WORDS]; - uECC_word_t *p2[2] = {tmp1, tmp2}; - uECC_word_t *initial_Z = 0; - uECC_word_t carry; - - /* Regularize the bitcount for the private key so that attackers cannot use a side channel - attack to learn the number of leading zeros. */ - carry = regularize_k(private_key, tmp1, tmp2, curve); - - /* If an RNG function was specified, try to get a random initial Z value to improve - protection against side-channel attacks. */ - if (g_rng_function) { - if (!uECC_generate_random_int(p2[carry], curve->p, curve->num_words)) { - return 0; - } - initial_Z = p2[carry]; - } - EccPoint_mult(result, curve->G, p2[!carry], initial_Z, curve->num_n_bits + 1, curve); - - if (EccPoint_isZero(result, curve)) { - return 0; - } - return 1; -} - -#if uECC_WORD_SIZE == 1 - -uECC_VLI_API void uECC_vli_nativeToBytes(uint8_t *bytes, - int num_bytes, - const uint8_t *native) { - wordcount_t i; - for (i = 0; i < num_bytes; ++i) { - bytes[i] = native[(num_bytes - 1) - i]; - } -} - -uECC_VLI_API void uECC_vli_bytesToNative(uint8_t *native, - const uint8_t *bytes, - int num_bytes) { - uECC_vli_nativeToBytes(native, num_bytes, bytes); -} - -#else - -uECC_VLI_API void uECC_vli_nativeToBytes(uint8_t *bytes, - int num_bytes, - const uECC_word_t *native) { - int i; - for (i = 0; i < num_bytes; ++i) { - unsigned b = num_bytes - 1 - i; - bytes[i] = native[b / uECC_WORD_SIZE] >> (8 * (b % uECC_WORD_SIZE)); - } -} - -uECC_VLI_API void uECC_vli_bytesToNative(uECC_word_t *native, - const uint8_t *bytes, - int num_bytes) { - int i; - uECC_vli_clear(native, (num_bytes + (uECC_WORD_SIZE - 1)) / uECC_WORD_SIZE); - for (i = 0; i < num_bytes; ++i) { - unsigned b = num_bytes - 1 - i; - native[b / uECC_WORD_SIZE] |= - (uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE)); - } -} - -#endif /* uECC_WORD_SIZE */ - -int uECC_make_key(uint8_t *public_key, - uint8_t *private_key, - uECC_Curve curve) { -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - uECC_word_t *_private = (uECC_word_t *)private_key; - uECC_word_t *_public = (uECC_word_t *)public_key; -#else - uECC_word_t _private[uECC_MAX_WORDS]; - uECC_word_t _public[uECC_MAX_WORDS * 2]; -#endif - uECC_word_t tries; - - for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { - if (!uECC_generate_random_int(_private, curve->n, BITS_TO_WORDS(curve->num_n_bits))) { - return 0; - } - - if (EccPoint_compute_public_key(_public, _private, curve)) { -#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0 - uECC_vli_nativeToBytes(private_key, BITS_TO_BYTES(curve->num_n_bits), _private); - uECC_vli_nativeToBytes(public_key, curve->num_bytes, _public); - uECC_vli_nativeToBytes( - public_key + curve->num_bytes, curve->num_bytes, _public + curve->num_words); -#endif - return 1; - } - } - return 0; -} - -int uECC_shared_secret(const uint8_t *public_key, - const uint8_t *private_key, - uint8_t *secret, - uECC_Curve curve) { - uECC_word_t _public[uECC_MAX_WORDS * 2]; - uECC_word_t _private[uECC_MAX_WORDS]; - - uECC_word_t tmp[uECC_MAX_WORDS]; - uECC_word_t *p2[2] = {_private, tmp}; - uECC_word_t *initial_Z = 0; - uECC_word_t carry; - wordcount_t num_words = curve->num_words; - wordcount_t num_bytes = curve->num_bytes; - -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - bcopy((uint8_t *) _private, private_key, num_bytes); - bcopy((uint8_t *) _public, public_key, num_bytes*2); -#else - uECC_vli_bytesToNative(_private, private_key, BITS_TO_BYTES(curve->num_n_bits)); - uECC_vli_bytesToNative(_public, public_key, num_bytes); - uECC_vli_bytesToNative(_public + num_words, public_key + num_bytes, num_bytes); -#endif - - /* Regularize the bitcount for the private key so that attackers cannot use a side channel - attack to learn the number of leading zeros. */ - carry = regularize_k(_private, _private, tmp, curve); - - /* If an RNG function was specified, try to get a random initial Z value to improve - protection against side-channel attacks. */ - if (g_rng_function) { - if (!uECC_generate_random_int(p2[carry], curve->p, num_words)) { - return 0; - } - initial_Z = p2[carry]; - } - - EccPoint_mult(_public, _public, p2[!carry], initial_Z, curve->num_n_bits + 1, curve); -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - bcopy((uint8_t *) secret, (uint8_t *) _public, num_bytes); -#else - uECC_vli_nativeToBytes(secret, num_bytes, _public); -#endif - return !EccPoint_isZero(_public, curve); -} - -#if uECC_SUPPORT_COMPRESSED_POINT -void uECC_compress(const uint8_t *public_key, uint8_t *compressed, uECC_Curve curve) { - wordcount_t i; - for (i = 0; i < curve->num_bytes; ++i) { - compressed[i+1] = public_key[i]; - } -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - compressed[0] = 2 + (public_key[curve->num_bytes] & 0x01); -#else - compressed[0] = 2 + (public_key[curve->num_bytes * 2 - 1] & 0x01); -#endif -} - -void uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve) { -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - uECC_word_t *point = (uECC_word_t *)public_key; -#else - uECC_word_t point[uECC_MAX_WORDS * 2]; -#endif - uECC_word_t *y = point + curve->num_words; -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - bcopy(public_key, compressed+1, curve->num_bytes); -#else - uECC_vli_bytesToNative(point, compressed + 1, curve->num_bytes); -#endif - curve->x_side(y, point, curve); - curve->mod_sqrt(y, curve); - - if ((y[0] & 0x01) != (compressed[0] & 0x01)) { - uECC_vli_sub(y, curve->p, y, curve->num_words); - } - -#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0 - uECC_vli_nativeToBytes(public_key, curve->num_bytes, point); - uECC_vli_nativeToBytes(public_key + curve->num_bytes, curve->num_bytes, y); -#endif -} -#endif /* uECC_SUPPORT_COMPRESSED_POINT */ - -uECC_VLI_API int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve) { - uECC_word_t tmp1[uECC_MAX_WORDS]; - uECC_word_t tmp2[uECC_MAX_WORDS]; - wordcount_t num_words = curve->num_words; - - /* The point at infinity is invalid. */ - if (EccPoint_isZero(point, curve)) { - return 0; - } - - /* x and y must be smaller than p. */ - if (uECC_vli_cmp_unsafe(curve->p, point, num_words) != 1 || - uECC_vli_cmp_unsafe(curve->p, point + num_words, num_words) != 1) { - return 0; - } - - uECC_vli_modSquare_fast(tmp1, point + num_words, curve); - curve->x_side(tmp2, point, curve); /* tmp2 = x^3 + ax + b */ - - /* Make sure that y^2 == x^3 + ax + b */ - return (int)(uECC_vli_equal(tmp1, tmp2, num_words)); -} - -int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve) { -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - uECC_word_t *_public = (uECC_word_t *)public_key; -#else - uECC_word_t _public[uECC_MAX_WORDS * 2]; -#endif - -#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0 - uECC_vli_bytesToNative(_public, public_key, curve->num_bytes); - uECC_vli_bytesToNative( - _public + curve->num_words, public_key + curve->num_bytes, curve->num_bytes); -#endif - return uECC_valid_point(_public, curve); -} - -int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve) { -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - uECC_word_t *_private = (uECC_word_t *)private_key; - uECC_word_t *_public = (uECC_word_t *)public_key; -#else - uECC_word_t _private[uECC_MAX_WORDS]; - uECC_word_t _public[uECC_MAX_WORDS * 2]; -#endif - -#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0 - uECC_vli_bytesToNative(_private, private_key, BITS_TO_BYTES(curve->num_n_bits)); -#endif - - /* Make sure the private key is in the range [1, n-1]. */ - if (uECC_vli_isZero(_private, BITS_TO_WORDS(curve->num_n_bits))) { - return 0; - } - - if (uECC_vli_cmp(curve->n, _private, BITS_TO_WORDS(curve->num_n_bits)) != 1) { - return 0; - } - - /* Compute public key. */ - if (!EccPoint_compute_public_key(_public, _private, curve)) { - return 0; - } - -#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0 - uECC_vli_nativeToBytes(public_key, curve->num_bytes, _public); - uECC_vli_nativeToBytes( - public_key + curve->num_bytes, curve->num_bytes, _public + curve->num_words); -#endif - return 1; -} - - -/* -------- ECDSA code -------- */ - -static void bits2int(uECC_word_t *native, - const uint8_t *bits, - unsigned bits_size, - uECC_Curve curve) { - unsigned num_n_bytes = BITS_TO_BYTES(curve->num_n_bits); - unsigned num_n_words = BITS_TO_WORDS(curve->num_n_bits); - int shift; - uECC_word_t carry; - uECC_word_t *ptr; - - if (bits_size > num_n_bytes) { - bits_size = num_n_bytes; - } - - uECC_vli_clear(native, num_n_words); -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - bcopy((uint8_t *) native, bits, bits_size); -#else - uECC_vli_bytesToNative(native, bits, bits_size); -#endif - if (bits_size * 8 <= (unsigned)curve->num_n_bits) { - return; - } - shift = bits_size * 8 - curve->num_n_bits; - carry = 0; - ptr = native + num_n_words; - while (ptr-- > native) { - uECC_word_t temp = *ptr; - *ptr = (temp >> shift) | carry; - carry = temp << (uECC_WORD_BITS - shift); - } - - /* Reduce mod curve_n */ - if (uECC_vli_cmp_unsafe(curve->n, native, num_n_words) != 1) { - uECC_vli_sub(native, native, curve->n, num_n_words); - } -} - -static int uECC_sign_with_k_internal(const uint8_t *private_key, - const uint8_t *message_hash, - unsigned hash_size, - uECC_word_t *k, - uint8_t *signature, - uECC_Curve curve) { - - uECC_word_t tmp[uECC_MAX_WORDS]; - uECC_word_t s[uECC_MAX_WORDS]; - uECC_word_t *k2[2] = {tmp, s}; - uECC_word_t *initial_Z = 0; -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - uECC_word_t *p = (uECC_word_t *)signature; -#else - uECC_word_t p[uECC_MAX_WORDS * 2]; -#endif - uECC_word_t carry; - wordcount_t num_words = curve->num_words; - wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); - bitcount_t num_n_bits = curve->num_n_bits; - - /* Make sure 0 < k < curve_n */ - if (uECC_vli_isZero(k, num_words) || uECC_vli_cmp(curve->n, k, num_n_words) != 1) { - return 0; - } - - carry = regularize_k(k, tmp, s, curve); - /* If an RNG function was specified, try to get a random initial Z value to improve - protection against side-channel attacks. */ - if (g_rng_function) { - if (!uECC_generate_random_int(k2[carry], curve->p, num_words)) { - return 0; - } - initial_Z = k2[carry]; - } - EccPoint_mult(p, curve->G, k2[!carry], initial_Z, num_n_bits + 1, curve); - if (uECC_vli_isZero(p, num_words)) { - return 0; - } - - /* If an RNG function was specified, get a random number - to prevent side channel analysis of k. */ - if (!g_rng_function) { - uECC_vli_clear(tmp, num_n_words); - tmp[0] = 1; - } else if (!uECC_generate_random_int(tmp, curve->n, num_n_words)) { - return 0; - } - - /* Prevent side channel analysis of uECC_vli_modInv() to determine - bits of k / the private key by premultiplying by a random number */ - uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k' = rand * k */ - uECC_vli_modInv(k, k, curve->n, num_n_words); /* k = 1 / k' */ - uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k = 1 / k */ - -#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0 - uECC_vli_nativeToBytes(signature, curve->num_bytes, p); /* store r */ -#endif - -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - bcopy((uint8_t *) tmp, private_key, BITS_TO_BYTES(curve->num_n_bits)); -#else - uECC_vli_bytesToNative(tmp, private_key, BITS_TO_BYTES(curve->num_n_bits)); /* tmp = d */ -#endif - - s[num_n_words - 1] = 0; - uECC_vli_set(s, p, num_words); - uECC_vli_modMult(s, tmp, s, curve->n, num_n_words); /* s = r*d */ - - bits2int(tmp, message_hash, hash_size, curve); - uECC_vli_modAdd(s, tmp, s, curve->n, num_n_words); /* s = e + r*d */ - uECC_vli_modMult(s, s, k, curve->n, num_n_words); /* s = (e + r*d) / k */ - if (uECC_vli_numBits(s, num_n_words) > (bitcount_t)curve->num_bytes * 8) { - return 0; - } -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - bcopy((uint8_t *) signature + curve->num_bytes, (uint8_t *) s, curve->num_bytes); -#else - uECC_vli_nativeToBytes(signature + curve->num_bytes, curve->num_bytes, s); -#endif - return 1; -} - -/* For testing - sign with an explicitly specified k value */ -int uECC_sign_with_k(const uint8_t *private_key, - const uint8_t *message_hash, - unsigned hash_size, - const uint8_t *k, - uint8_t *signature, - uECC_Curve curve) { - uECC_word_t k2[uECC_MAX_WORDS]; - bits2int(k2, k, BITS_TO_BYTES(curve->num_n_bits), curve); - return uECC_sign_with_k_internal(private_key, message_hash, hash_size, k2, signature, curve); -} - -int uECC_sign(const uint8_t *private_key, - const uint8_t *message_hash, - unsigned hash_size, - uint8_t *signature, - uECC_Curve curve) { - uECC_word_t k[uECC_MAX_WORDS]; - uECC_word_t tries; - - for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { - if (!uECC_generate_random_int(k, curve->n, BITS_TO_WORDS(curve->num_n_bits))) { - return 0; - } - - if (uECC_sign_with_k_internal(private_key, message_hash, hash_size, k, signature, curve)) { - return 1; - } - } - return 0; -} - -/* Compute an HMAC using K as a key (as in RFC 6979). Note that K is always - the same size as the hash result size. */ -static void HMAC_init(const uECC_HashContext *hash_context, const uint8_t *K) { - uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size; - unsigned i; - for (i = 0; i < hash_context->result_size; ++i) - pad[i] = K[i] ^ 0x36; - for (; i < hash_context->block_size; ++i) - pad[i] = 0x36; - - hash_context->init_hash(hash_context); - hash_context->update_hash(hash_context, pad, hash_context->block_size); -} - -static void HMAC_update(const uECC_HashContext *hash_context, - const uint8_t *message, - unsigned message_size) { - hash_context->update_hash(hash_context, message, message_size); -} - -static void HMAC_finish(const uECC_HashContext *hash_context, - const uint8_t *K, - uint8_t *result) { - uint8_t *pad = hash_context->tmp + 2 * hash_context->result_size; - unsigned i; - for (i = 0; i < hash_context->result_size; ++i) - pad[i] = K[i] ^ 0x5c; - for (; i < hash_context->block_size; ++i) - pad[i] = 0x5c; - - hash_context->finish_hash(hash_context, result); - - hash_context->init_hash(hash_context); - hash_context->update_hash(hash_context, pad, hash_context->block_size); - hash_context->update_hash(hash_context, result, hash_context->result_size); - hash_context->finish_hash(hash_context, result); -} - -/* V = HMAC_K(V) */ -static void update_V(const uECC_HashContext *hash_context, uint8_t *K, uint8_t *V) { - HMAC_init(hash_context, K); - HMAC_update(hash_context, V, hash_context->result_size); - HMAC_finish(hash_context, K, V); -} - -/* Deterministic signing, similar to RFC 6979. Differences are: - * We just use H(m) directly rather than bits2octets(H(m)) - (it is not reduced modulo curve_n). - * We generate a value for k (aka T) directly rather than converting endianness. - - Layout of hash_context->tmp: | | (1 byte overlapped 0x00 or 0x01) / */ -int uECC_sign_deterministic(const uint8_t *private_key, - const uint8_t *message_hash, - unsigned hash_size, - const uECC_HashContext *hash_context, - uint8_t *signature, - uECC_Curve curve) { - uint8_t *K = hash_context->tmp; - uint8_t *V = K + hash_context->result_size; - wordcount_t num_bytes = curve->num_bytes; - wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); - bitcount_t num_n_bits = curve->num_n_bits; - uECC_word_t tries; - unsigned i; - for (i = 0; i < hash_context->result_size; ++i) { - V[i] = 0x01; - K[i] = 0; - } - - /* K = HMAC_K(V || 0x00 || int2octets(x) || h(m)) */ - HMAC_init(hash_context, K); - V[hash_context->result_size] = 0x00; - HMAC_update(hash_context, V, hash_context->result_size + 1); - HMAC_update(hash_context, private_key, num_bytes); - HMAC_update(hash_context, message_hash, hash_size); - HMAC_finish(hash_context, K, K); - - update_V(hash_context, K, V); - - /* K = HMAC_K(V || 0x01 || int2octets(x) || h(m)) */ - HMAC_init(hash_context, K); - V[hash_context->result_size] = 0x01; - HMAC_update(hash_context, V, hash_context->result_size + 1); - HMAC_update(hash_context, private_key, num_bytes); - HMAC_update(hash_context, message_hash, hash_size); - HMAC_finish(hash_context, K, K); - - update_V(hash_context, K, V); - - for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { - uECC_word_t T[uECC_MAX_WORDS]; - uint8_t *T_ptr = (uint8_t *)T; - wordcount_t T_bytes = 0; - for (;;) { - update_V(hash_context, K, V); - for (i = 0; i < hash_context->result_size; ++i) { - T_ptr[T_bytes++] = V[i]; - if (T_bytes >= num_n_words * uECC_WORD_SIZE) { - goto filled; - } - } - } - filled: - if ((bitcount_t)num_n_words * uECC_WORD_SIZE * 8 > num_n_bits) { - uECC_word_t mask = (uECC_word_t)-1; - T[num_n_words - 1] &= - mask >> ((bitcount_t)(num_n_words * uECC_WORD_SIZE * 8 - num_n_bits)); - } - - if (uECC_sign_with_k_internal(private_key, message_hash, hash_size, T, signature, curve)) { - return 1; - } - - /* K = HMAC_K(V || 0x00) */ - HMAC_init(hash_context, K); - V[hash_context->result_size] = 0x00; - HMAC_update(hash_context, V, hash_context->result_size + 1); - HMAC_finish(hash_context, K, K); - - update_V(hash_context, K, V); - } - return 0; -} - -static bitcount_t smax(bitcount_t a, bitcount_t b) { - return (a > b ? a : b); -} - -int uECC_verify(const uint8_t *public_key, - const uint8_t *message_hash, - unsigned hash_size, - const uint8_t *signature, - uECC_Curve curve) { - uECC_word_t u1[uECC_MAX_WORDS], u2[uECC_MAX_WORDS]; - uECC_word_t z[uECC_MAX_WORDS]; - uECC_word_t sum[uECC_MAX_WORDS * 2]; - uECC_word_t rx[uECC_MAX_WORDS]; - uECC_word_t ry[uECC_MAX_WORDS]; - uECC_word_t tx[uECC_MAX_WORDS]; - uECC_word_t ty[uECC_MAX_WORDS]; - uECC_word_t tz[uECC_MAX_WORDS]; - const uECC_word_t *points[4]; - const uECC_word_t *point; - bitcount_t num_bits; - bitcount_t i; -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - uECC_word_t *_public = (uECC_word_t *)public_key; -#else - uECC_word_t _public[uECC_MAX_WORDS * 2]; -#endif - uECC_word_t r[uECC_MAX_WORDS], s[uECC_MAX_WORDS]; - wordcount_t num_words = curve->num_words; - wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); - - rx[num_n_words - 1] = 0; - r[num_n_words - 1] = 0; - s[num_n_words - 1] = 0; - -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - bcopy((uint8_t *) r, signature, curve->num_bytes); - bcopy((uint8_t *) s, signature + curve->num_bytes, curve->num_bytes); -#else - uECC_vli_bytesToNative(_public, public_key, curve->num_bytes); - uECC_vli_bytesToNative( - _public + num_words, public_key + curve->num_bytes, curve->num_bytes); - uECC_vli_bytesToNative(r, signature, curve->num_bytes); - uECC_vli_bytesToNative(s, signature + curve->num_bytes, curve->num_bytes); -#endif - - /* r, s must not be 0. */ - if (uECC_vli_isZero(r, num_words) || uECC_vli_isZero(s, num_words)) { - return 0; - } - - /* r, s must be < n. */ - if (uECC_vli_cmp_unsafe(curve->n, r, num_n_words) != 1 || - uECC_vli_cmp_unsafe(curve->n, s, num_n_words) != 1) { - return 0; - } - - /* Calculate u1 and u2. */ - uECC_vli_modInv(z, s, curve->n, num_n_words); /* z = 1/s */ - u1[num_n_words - 1] = 0; - bits2int(u1, message_hash, hash_size, curve); - uECC_vli_modMult(u1, u1, z, curve->n, num_n_words); /* u1 = e/s */ - uECC_vli_modMult(u2, r, z, curve->n, num_n_words); /* u2 = r/s */ - - /* Calculate sum = G + Q. */ - uECC_vli_set(sum, _public, num_words); - uECC_vli_set(sum + num_words, _public + num_words, num_words); - uECC_vli_set(tx, curve->G, num_words); - uECC_vli_set(ty, curve->G + num_words, num_words); - uECC_vli_modSub(z, sum, tx, curve->p, num_words); /* z = x2 - x1 */ - XYcZ_add(tx, ty, sum, sum + num_words, curve); - uECC_vli_modInv(z, z, curve->p, num_words); /* z = 1/z */ - apply_z(sum, sum + num_words, z, curve); - - /* Use Shamir's trick to calculate u1*G + u2*Q */ - points[0] = 0; - points[1] = curve->G; - points[2] = _public; - points[3] = sum; - num_bits = smax(uECC_vli_numBits(u1, num_n_words), - uECC_vli_numBits(u2, num_n_words)); - - point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) | - ((!!uECC_vli_testBit(u2, num_bits - 1)) << 1)]; - uECC_vli_set(rx, point, num_words); - uECC_vli_set(ry, point + num_words, num_words); - uECC_vli_clear(z, num_words); - z[0] = 1; - - for (i = num_bits - 2; i >= 0; --i) { - uECC_word_t index; - curve->double_jacobian(rx, ry, z, curve); - - index = (!!uECC_vli_testBit(u1, i)) | ((!!uECC_vli_testBit(u2, i)) << 1); - point = points[index]; - if (point) { - uECC_vli_set(tx, point, num_words); - uECC_vli_set(ty, point + num_words, num_words); - apply_z(tx, ty, z, curve); - uECC_vli_modSub(tz, rx, tx, curve->p, num_words); /* Z = x2 - x1 */ - XYcZ_add(tx, ty, rx, ry, curve); - uECC_vli_modMult_fast(z, z, tz, curve); - } - } - - uECC_vli_modInv(z, z, curve->p, num_words); /* Z = 1/Z */ - apply_z(rx, ry, z, curve); - - /* v = x1 (mod n) */ - if (uECC_vli_cmp_unsafe(curve->n, rx, num_n_words) != 1) { - uECC_vli_sub(rx, rx, curve->n, num_n_words); - } - - /* Accept only if v == r. */ - return (int)(uECC_vli_equal(rx, r, num_words)); -} - -#if uECC_ENABLE_VLI_API - -unsigned uECC_curve_num_words(uECC_Curve curve) { - return curve->num_words; -} - -unsigned uECC_curve_num_bytes(uECC_Curve curve) { - return curve->num_bytes; -} - -unsigned uECC_curve_num_bits(uECC_Curve curve) { - return curve->num_bytes * 8; -} - -unsigned uECC_curve_num_n_words(uECC_Curve curve) { - return BITS_TO_WORDS(curve->num_n_bits); -} - -unsigned uECC_curve_num_n_bytes(uECC_Curve curve) { - return BITS_TO_BYTES(curve->num_n_bits); -} - -unsigned uECC_curve_num_n_bits(uECC_Curve curve) { - return curve->num_n_bits; -} - -const uECC_word_t *uECC_curve_p(uECC_Curve curve) { - return curve->p; -} - -const uECC_word_t *uECC_curve_n(uECC_Curve curve) { - return curve->n; -} - -const uECC_word_t *uECC_curve_G(uECC_Curve curve) { - return curve->G; -} - -const uECC_word_t *uECC_curve_b(uECC_Curve curve) { - return curve->b; -} - -#if uECC_SUPPORT_COMPRESSED_POINT -void uECC_vli_mod_sqrt(uECC_word_t *a, uECC_Curve curve) { - curve->mod_sqrt(a, curve); -} -#endif - -void uECC_vli_mmod_fast(uECC_word_t *result, uECC_word_t *product, uECC_Curve curve) { -#if (uECC_OPTIMIZATION_LEVEL > 0) - curve->mmod_fast(result, product); -#else - uECC_vli_mmod(result, product, curve->p, curve->num_words); -#endif -} - -void uECC_point_mult(uECC_word_t *result, - const uECC_word_t *point, - const uECC_word_t *scalar, - uECC_Curve curve) { - uECC_word_t tmp1[uECC_MAX_WORDS]; - uECC_word_t tmp2[uECC_MAX_WORDS]; - uECC_word_t *p2[2] = {tmp1, tmp2}; - uECC_word_t carry = regularize_k(scalar, tmp1, tmp2, curve); - - EccPoint_mult(result, point, p2[!carry], 0, curve->num_n_bits + 1, curve); -} - -#endif /* uECC_ENABLE_VLI_API */ diff --git a/lib/micro-ecc/uECC.h b/lib/micro-ecc/uECC.h deleted file mode 100644 index dcbdbfa8b42..00000000000 --- a/lib/micro-ecc/uECC.h +++ /dev/null @@ -1,367 +0,0 @@ -/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */ - -#ifndef _UECC_H_ -#define _UECC_H_ - -#include - -/* Platform selection options. -If uECC_PLATFORM is not defined, the code will try to guess it based on compiler macros. -Possible values for uECC_PLATFORM are defined below: */ -#define uECC_arch_other 0 -#define uECC_x86 1 -#define uECC_x86_64 2 -#define uECC_arm 3 -#define uECC_arm_thumb 4 -#define uECC_arm_thumb2 5 -#define uECC_arm64 6 -#define uECC_avr 7 - -/* If desired, you can define uECC_WORD_SIZE as appropriate for your platform (1, 4, or 8 bytes). -If uECC_WORD_SIZE is not explicitly defined then it will be automatically set based on your -platform. */ - -/* Optimization level; trade speed for code size. - Larger values produce code that is faster but larger. - Currently supported values are 0 - 4; 0 is unusably slow for most applications. - Optimization level 4 currently only has an effect ARM platforms where more than one - curve is enabled. */ -#ifndef uECC_OPTIMIZATION_LEVEL - #define uECC_OPTIMIZATION_LEVEL 2 -#endif - -/* uECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a specific function to be -used for (scalar) squaring instead of the generic multiplication function. This can make things -faster somewhat faster, but increases the code size. */ -#ifndef uECC_SQUARE_FUNC - #define uECC_SQUARE_FUNC 0 -#endif - -/* uECC_VLI_NATIVE_LITTLE_ENDIAN - If enabled (defined as nonzero), this will switch to native -little-endian format for *all* arrays passed in and out of the public API. This includes public -and private keys, shared secrets, signatures and message hashes. -Using this switch reduces the amount of call stack memory used by uECC, since less intermediate -translations are required. -Note that this will *only* work on native little-endian processors and it will treat the uint8_t -arrays passed into the public API as word arrays, therefore requiring the provided byte arrays -to be word aligned on architectures that do not support unaligned accesses. -IMPORTANT: Keys and signatures generated with uECC_VLI_NATIVE_LITTLE_ENDIAN=1 are incompatible -with keys and signatures generated with uECC_VLI_NATIVE_LITTLE_ENDIAN=0; all parties must use -the same endianness. */ -#ifndef uECC_VLI_NATIVE_LITTLE_ENDIAN - #define uECC_VLI_NATIVE_LITTLE_ENDIAN 0 -#endif - -/* Curve support selection. Set to 0 to remove that curve. */ -#ifndef uECC_SUPPORTS_secp160r1 - #define uECC_SUPPORTS_secp160r1 1 -#endif -#ifndef uECC_SUPPORTS_secp192r1 - #define uECC_SUPPORTS_secp192r1 1 -#endif -#ifndef uECC_SUPPORTS_secp224r1 - #define uECC_SUPPORTS_secp224r1 1 -#endif -#ifndef uECC_SUPPORTS_secp256r1 - #define uECC_SUPPORTS_secp256r1 1 -#endif -#ifndef uECC_SUPPORTS_secp256k1 - #define uECC_SUPPORTS_secp256k1 1 -#endif - -/* Specifies whether compressed point format is supported. - Set to 0 to disable point compression/decompression functions. */ -#ifndef uECC_SUPPORT_COMPRESSED_POINT - #define uECC_SUPPORT_COMPRESSED_POINT 1 -#endif - -struct uECC_Curve_t; -typedef const struct uECC_Curve_t * uECC_Curve; - -#ifdef __cplusplus -extern "C" -{ -#endif - -#if uECC_SUPPORTS_secp160r1 -uECC_Curve uECC_secp160r1(void); -#endif -#if uECC_SUPPORTS_secp192r1 -uECC_Curve uECC_secp192r1(void); -#endif -#if uECC_SUPPORTS_secp224r1 -uECC_Curve uECC_secp224r1(void); -#endif -#if uECC_SUPPORTS_secp256r1 -uECC_Curve uECC_secp256r1(void); -#endif -#if uECC_SUPPORTS_secp256k1 -uECC_Curve uECC_secp256k1(void); -#endif - -/* uECC_RNG_Function type -The RNG function should fill 'size' random bytes into 'dest'. It should return 1 if -'dest' was filled with random data, or 0 if the random data could not be generated. -The filled-in values should be either truly random, or from a cryptographically-secure PRNG. - -A correctly functioning RNG function must be set (using uECC_set_rng()) before calling -uECC_make_key() or uECC_sign(). - -Setting a correctly functioning RNG function improves the resistance to side-channel attacks -for uECC_shared_secret() and uECC_sign_deterministic(). - -A correct RNG function is set by default when building for Windows, Linux, or OS X. -If you are building on another POSIX-compliant system that supports /dev/random or /dev/urandom, -you can define uECC_POSIX to use the predefined RNG. For embedded platforms there is no predefined -RNG function; you must provide your own. -*/ -typedef int (*uECC_RNG_Function)(uint8_t *dest, unsigned size); - -/* uECC_set_rng() function. -Set the function that will be used to generate random bytes. The RNG function should -return 1 if the random data was generated, or 0 if the random data could not be generated. - -On platforms where there is no predefined RNG function (eg embedded platforms), this must -be called before uECC_make_key() or uECC_sign() are used. - -Inputs: - rng_function - The function that will be used to generate random bytes. -*/ -void uECC_set_rng(uECC_RNG_Function rng_function); - -/* uECC_get_rng() function. - -Returns the function that will be used to generate random bytes. -*/ -uECC_RNG_Function uECC_get_rng(void); - -/* uECC_curve_private_key_size() function. - -Returns the size of a private key for the curve in bytes. -*/ -int uECC_curve_private_key_size(uECC_Curve curve); - -/* uECC_curve_public_key_size() function. - -Returns the size of a public key for the curve in bytes. -*/ -int uECC_curve_public_key_size(uECC_Curve curve); - -/* uECC_make_key() function. -Create a public/private key pair. - -Outputs: - public_key - Will be filled in with the public key. Must be at least 2 * the curve size - (in bytes) long. For example, if the curve is secp256r1, public_key must be 64 - bytes long. - private_key - Will be filled in with the private key. Must be as long as the curve order; this - is typically the same as the curve size, except for secp160r1. For example, if the - curve is secp256r1, private_key must be 32 bytes long. - - For secp160r1, private_key must be 21 bytes long! Note that the first byte will - almost always be 0 (there is about a 1 in 2^80 chance of it being non-zero). - -Returns 1 if the key pair was generated successfully, 0 if an error occurred. -*/ -int uECC_make_key(uint8_t *public_key, uint8_t *private_key, uECC_Curve curve); - -/* uECC_shared_secret() function. -Compute a shared secret given your secret key and someone else's public key. If the public key -is not from a trusted source and has not been previously verified, you should verify it first -using uECC_valid_public_key(). -Note: It is recommended that you hash the result of uECC_shared_secret() before using it for -symmetric encryption or HMAC. - -Inputs: - public_key - The public key of the remote party. - private_key - Your private key. - -Outputs: - secret - Will be filled in with the shared secret value. Must be the same size as the - curve size; for example, if the curve is secp256r1, secret must be 32 bytes long. - -Returns 1 if the shared secret was generated successfully, 0 if an error occurred. -*/ -int uECC_shared_secret(const uint8_t *public_key, - const uint8_t *private_key, - uint8_t *secret, - uECC_Curve curve); - -#if uECC_SUPPORT_COMPRESSED_POINT -/* uECC_compress() function. -Compress a public key. - -Inputs: - public_key - The public key to compress. - -Outputs: - compressed - Will be filled in with the compressed public key. Must be at least - (curve size + 1) bytes long; for example, if the curve is secp256r1, - compressed must be 33 bytes long. -*/ -void uECC_compress(const uint8_t *public_key, uint8_t *compressed, uECC_Curve curve); - -/* uECC_decompress() function. -Decompress a compressed public key. - -Inputs: - compressed - The compressed public key. - -Outputs: - public_key - Will be filled in with the decompressed public key. -*/ -void uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve); -#endif /* uECC_SUPPORT_COMPRESSED_POINT */ - -/* uECC_valid_public_key() function. -Check to see if a public key is valid. - -Note that you are not required to check for a valid public key before using any other uECC -functions. However, you may wish to avoid spending CPU time computing a shared secret or -verifying a signature using an invalid public key. - -Inputs: - public_key - The public key to check. - -Returns 1 if the public key is valid, 0 if it is invalid. -*/ -int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve); - -/* uECC_compute_public_key() function. -Compute the corresponding public key for a private key. - -Inputs: - private_key - The private key to compute the public key for - -Outputs: - public_key - Will be filled in with the corresponding public key - -Returns 1 if the key was computed successfully, 0 if an error occurred. -*/ -int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve); - -/* uECC_sign() function. -Generate an ECDSA signature for a given hash value. - -Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to -this function along with your private key. - -Inputs: - private_key - Your private key. - message_hash - The hash of the message to sign. - hash_size - The size of message_hash in bytes. - -Outputs: - signature - Will be filled in with the signature value. Must be at least 2 * curve size long. - For example, if the curve is secp256r1, signature must be 64 bytes long. - -Returns 1 if the signature generated successfully, 0 if an error occurred. -*/ -int uECC_sign(const uint8_t *private_key, - const uint8_t *message_hash, - unsigned hash_size, - uint8_t *signature, - uECC_Curve curve); - -/* uECC_HashContext structure. -This is used to pass in an arbitrary hash function to uECC_sign_deterministic(). -The structure will be used for multiple hash computations; each time a new hash -is computed, init_hash() will be called, followed by one or more calls to -update_hash(), and finally a call to finish_hash() to produce the resulting hash. - -The intention is that you will create a structure that includes uECC_HashContext -followed by any hash-specific data. For example: - -typedef struct SHA256_HashContext { - uECC_HashContext uECC; - SHA256_CTX ctx; -} SHA256_HashContext; - -void init_SHA256(uECC_HashContext *base) { - SHA256_HashContext *context = (SHA256_HashContext *)base; - SHA256_Init(&context->ctx); -} - -void update_SHA256(uECC_HashContext *base, - const uint8_t *message, - unsigned message_size) { - SHA256_HashContext *context = (SHA256_HashContext *)base; - SHA256_Update(&context->ctx, message, message_size); -} - -void finish_SHA256(uECC_HashContext *base, uint8_t *hash_result) { - SHA256_HashContext *context = (SHA256_HashContext *)base; - SHA256_Final(hash_result, &context->ctx); -} - -... when signing ... -{ - uint8_t tmp[32 + 32 + 64]; - SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64, 32, tmp}}; - uECC_sign_deterministic(key, message_hash, &ctx.uECC, signature); -} -*/ -typedef struct uECC_HashContext { - void (*init_hash)(const struct uECC_HashContext *context); - void (*update_hash)(const struct uECC_HashContext *context, - const uint8_t *message, - unsigned message_size); - void (*finish_hash)(const struct uECC_HashContext *context, uint8_t *hash_result); - unsigned block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */ - unsigned result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */ - uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size + block_size) bytes. */ -} uECC_HashContext; - -/* uECC_sign_deterministic() function. -Generate an ECDSA signature for a given hash value, using a deterministic algorithm -(see RFC 6979). You do not need to set the RNG using uECC_set_rng() before calling -this function; however, if the RNG is defined it will improve resistance to side-channel -attacks. - -Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it to -this function along with your private key and a hash context. Note that the message_hash -does not need to be computed with the same hash function used by hash_context. - -Inputs: - private_key - Your private key. - message_hash - The hash of the message to sign. - hash_size - The size of message_hash in bytes. - hash_context - A hash context to use. - -Outputs: - signature - Will be filled in with the signature value. - -Returns 1 if the signature generated successfully, 0 if an error occurred. -*/ -int uECC_sign_deterministic(const uint8_t *private_key, - const uint8_t *message_hash, - unsigned hash_size, - const uECC_HashContext *hash_context, - uint8_t *signature, - uECC_Curve curve); - -/* uECC_verify() function. -Verify an ECDSA signature. - -Usage: Compute the hash of the signed data using the same hash as the signer and -pass it to this function along with the signer's public key and the signature values (r and s). - -Inputs: - public_key - The signer's public key. - message_hash - The hash of the signed data. - hash_size - The size of message_hash in bytes. - signature - The signature value. - -Returns 1 if the signature is valid, 0 if it is invalid. -*/ -int uECC_verify(const uint8_t *public_key, - const uint8_t *message_hash, - unsigned hash_size, - const uint8_t *signature, - uECC_Curve curve); - -#ifdef __cplusplus -} /* end of extern "C" */ -#endif - -#endif /* _UECC_H_ */ diff --git a/lib/micro-ecc/uECC_vli.h b/lib/micro-ecc/uECC_vli.h deleted file mode 100644 index 864cc333569..00000000000 --- a/lib/micro-ecc/uECC_vli.h +++ /dev/null @@ -1,172 +0,0 @@ -/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */ - -#ifndef _UECC_VLI_H_ -#define _UECC_VLI_H_ - -#include "uECC.h" -#include "types.h" - -/* Functions for raw large-integer manipulation. These are only available - if uECC.c is compiled with uECC_ENABLE_VLI_API defined to 1. */ -#ifndef uECC_ENABLE_VLI_API - #define uECC_ENABLE_VLI_API 0 -#endif - -#ifdef __cplusplus -extern "C" -{ -#endif - -#if uECC_ENABLE_VLI_API - -void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words); - -/* Constant-time comparison to zero - secure way to compare long integers */ -/* Returns 1 if vli == 0, 0 otherwise. */ -uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words); - -/* Returns nonzero if bit 'bit' of vli is set. */ -uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit); - -/* Counts the number of bits required to represent vli. */ -bitcount_t uECC_vli_numBits(const uECC_word_t *vli, const wordcount_t max_words); - -/* Sets dest = src. */ -void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, wordcount_t num_words); - -/* Constant-time comparison function - secure way to compare long integers */ -/* Returns one if left == right, zero otherwise */ -uECC_word_t uECC_vli_equal(const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words); - -/* Constant-time comparison function - secure way to compare long integers */ -/* Returns sign of left - right, in constant time. */ -cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right, wordcount_t num_words); - -/* Computes vli = vli >> 1. */ -void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words); - -/* Computes result = left + right, returning carry. Can modify in place. */ -uECC_word_t uECC_vli_add(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words); - -/* Computes result = left - right, returning borrow. Can modify in place. */ -uECC_word_t uECC_vli_sub(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words); - -/* Computes result = left * right. Result must be 2 * num_words long. */ -void uECC_vli_mult(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - wordcount_t num_words); - -/* Computes result = left^2. Result must be 2 * num_words long. */ -void uECC_vli_square(uECC_word_t *result, const uECC_word_t *left, wordcount_t num_words); - -/* Computes result = (left + right) % mod. - Assumes that left < mod and right < mod, and that result does not overlap mod. */ -void uECC_vli_modAdd(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - const uECC_word_t *mod, - wordcount_t num_words); - -/* Computes result = (left - right) % mod. - Assumes that left < mod and right < mod, and that result does not overlap mod. */ -void uECC_vli_modSub(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - const uECC_word_t *mod, - wordcount_t num_words); - -/* Computes result = product % mod, where product is 2N words long. - Currently only designed to work for mod == curve->p or curve_n. */ -void uECC_vli_mmod(uECC_word_t *result, - uECC_word_t *product, - const uECC_word_t *mod, - wordcount_t num_words); - -/* Calculates result = product (mod curve->p), where product is up to - 2 * curve->num_words long. */ -void uECC_vli_mmod_fast(uECC_word_t *result, uECC_word_t *product, uECC_Curve curve); - -/* Computes result = (left * right) % mod. - Currently only designed to work for mod == curve->p or curve_n. */ -void uECC_vli_modMult(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - const uECC_word_t *mod, - wordcount_t num_words); - -/* Computes result = (left * right) % curve->p. */ -void uECC_vli_modMult_fast(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *right, - uECC_Curve curve); - -/* Computes result = left^2 % mod. - Currently only designed to work for mod == curve->p or curve_n. */ -void uECC_vli_modSquare(uECC_word_t *result, - const uECC_word_t *left, - const uECC_word_t *mod, - wordcount_t num_words); - -/* Computes result = left^2 % curve->p. */ -void uECC_vli_modSquare_fast(uECC_word_t *result, const uECC_word_t *left, uECC_Curve curve); - -/* Computes result = (1 / input) % mod.*/ -void uECC_vli_modInv(uECC_word_t *result, - const uECC_word_t *input, - const uECC_word_t *mod, - wordcount_t num_words); - -#if uECC_SUPPORT_COMPRESSED_POINT -/* Calculates a = sqrt(a) (mod curve->p) */ -void uECC_vli_mod_sqrt(uECC_word_t *a, uECC_Curve curve); -#endif - -/* Converts an integer in uECC native format to big-endian bytes. */ -void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes, const uECC_word_t *native); -/* Converts big-endian bytes to an integer in uECC native format. */ -void uECC_vli_bytesToNative(uECC_word_t *native, const uint8_t *bytes, int num_bytes); - -unsigned uECC_curve_num_words(uECC_Curve curve); -unsigned uECC_curve_num_bytes(uECC_Curve curve); -unsigned uECC_curve_num_bits(uECC_Curve curve); -unsigned uECC_curve_num_n_words(uECC_Curve curve); -unsigned uECC_curve_num_n_bytes(uECC_Curve curve); -unsigned uECC_curve_num_n_bits(uECC_Curve curve); - -const uECC_word_t *uECC_curve_p(uECC_Curve curve); -const uECC_word_t *uECC_curve_n(uECC_Curve curve); -const uECC_word_t *uECC_curve_G(uECC_Curve curve); -const uECC_word_t *uECC_curve_b(uECC_Curve curve); - -int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve); - -/* Multiplies a point by a scalar. Points are represented by the X coordinate followed by - the Y coordinate in the same array, both coordinates are curve->num_words long. Note - that scalar must be curve->num_n_words long (NOT curve->num_words). */ -void uECC_point_mult(uECC_word_t *result, - const uECC_word_t *point, - const uECC_word_t *scalar, - uECC_Curve curve); - -/* Generates a random integer in the range 0 < random < top. - Both random and top have num_words words. */ -int uECC_generate_random_int(uECC_word_t *random, - const uECC_word_t *top, - wordcount_t num_words); - -#endif /* uECC_ENABLE_VLI_API */ - -#ifdef __cplusplus -} /* end of extern "C" */ -#endif - -#endif /* _UECC_VLI_H_ */ diff --git a/lib/microtar.scons b/lib/microtar.scons index 6ee36d403cd..54949fb42b6 100644 --- a/lib/microtar.scons +++ b/lib/microtar.scons @@ -14,7 +14,7 @@ libenv.Append( CPPDEFINES=["MICROTAR_DISABLE_API_CHECKS"], ) -sources = libenv.GlobRecursive("*.c", "microtar/src") +sources = [File("microtar/src/microtar.c")] lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) libenv.Install("${LIB_DIST_DIR}", lib) diff --git a/lib/misc.scons b/lib/misc.scons deleted file mode 100644 index 92fa5a106ff..00000000000 --- a/lib/misc.scons +++ /dev/null @@ -1,58 +0,0 @@ -from fbt.util import GLOB_FILE_EXCLUSION - -Import("env") - -env.Append( - CPPPATH=[ - "#/lib/fnv1a_hash", - "#/lib/heatshrink", - "#/lib/micro-ecc", - "#/lib/nanopb", - "#/lib/u8g2", - ], - CPPDEFINES=[ - "PB_ENABLE_MALLOC", - ], - SDK_HEADERS=[ - File("micro-ecc/uECC.h"), - File("nanopb/pb.h"), - File("nanopb/pb_decode.h"), - File("nanopb/pb_encode.h"), - ], -) - - -libenv = env.Clone(FW_LIB_NAME="misc") -libenv.ApplyLibFlags() - -sources = [] - -libs_recurse = [ - "micro-ecc", - "u8g2", - "update_util", -] - -for lib in libs_recurse: - sources += libenv.GlobRecursive("*.c*", lib) - -libs_plain = [ - "nanopb", -] - -for lib in libs_plain: - sources += Glob( - lib + "/*.c*", - exclude=GLOB_FILE_EXCLUSION, - source=True, - ) - -sources += Glob( - "heatshrink/heatshrink_*.c*", - exclude=GLOB_FILE_EXCLUSION, - source=True, -) - -lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) -libenv.Install("${LIB_DIST_DIR}", lib) -Return("lib") diff --git a/lib/mlib.scons b/lib/mlib.scons new file mode 100644 index 00000000000..2bdd3728955 --- /dev/null +++ b/lib/mlib.scons @@ -0,0 +1,27 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/mlib", + ], + SDK_HEADERS=[ + *( + File(f"#/lib/mlib/m-{name}.h") + for name in ( + "algo", + "array", + "bptree", + "core", + "deque", + "dict", + "list", + "rbtree", + "tuple", + "variant", + ) + ), + ], + CPPDEFINES=[ + '"M_MEMORY_FULL(x)=abort()"', + ], +) diff --git a/lib/music_worker/SConscript b/lib/music_worker/SConscript index 36d01d8596a..0439286cebf 100644 --- a/lib/music_worker/SConscript +++ b/lib/music_worker/SConscript @@ -7,6 +7,9 @@ env.Append( SDK_HEADERS=[ File("music_worker.h"), ], + LINT_SOURCES=[ + Dir("."), + ], ) libenv = env.Clone(FW_LIB_NAME="music_worker") diff --git a/lib/nanopb.scons b/lib/nanopb.scons new file mode 100644 index 00000000000..43e828b85e6 --- /dev/null +++ b/lib/nanopb.scons @@ -0,0 +1,31 @@ +from fbt.util import GLOB_FILE_EXCLUSION + +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/nanopb", + ], + CPPDEFINES=[ + "PB_ENABLE_MALLOC", + ], + SDK_HEADERS=[ + File("nanopb/pb.h"), + File("nanopb/pb_decode.h"), + File("nanopb/pb_encode.h"), + ], +) + + +libenv = env.Clone(FW_LIB_NAME="nanopb") +libenv.ApplyLibFlags() + +sources = Glob( + "nanopb/*.c*", + exclude=GLOB_FILE_EXCLUSION, + source=True, +) + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/nfc/SConscript b/lib/nfc/SConscript index 605a8639dd8..21f2fb49f6a 100644 --- a/lib/nfc/SConscript +++ b/lib/nfc/SConscript @@ -4,6 +4,9 @@ env.Append( CPPPATH=[ "#/lib/nfc", ], + LINT_SOURCES=[ + Dir("."), + ], SDK_HEADERS=[ # Main File("nfc.h"), diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c index 129dcdf5e1d..8e65eca5a54 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_i.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_i.c @@ -56,7 +56,7 @@ bool mf_desfire_version_parse(MfDesfireVersion* data, const BitBuffer* buf) { } bool mf_desfire_free_memory_parse(MfDesfireFreeMemory* data, const BitBuffer* buf) { - typedef struct __attribute__((packed)) { + typedef struct FURI_PACKED { uint32_t bytes_free : 3 * BITS_IN_BYTE; } MfDesfireFreeMemoryLayout; @@ -74,7 +74,7 @@ bool mf_desfire_free_memory_parse(MfDesfireFreeMemory* data, const BitBuffer* bu } bool mf_desfire_key_settings_parse(MfDesfireKeySettings* data, const BitBuffer* buf) { - typedef struct __attribute__((packed)) { + typedef struct FURI_PACKED { bool is_master_key_changeable : 1; bool is_free_directory_list : 1; bool is_free_create_delete : 1; @@ -143,30 +143,30 @@ bool mf_desfire_file_id_parse(MfDesfireFileId* data, uint32_t index, const BitBu bool mf_desfire_file_settings_parse(MfDesfireFileSettings* data, const BitBuffer* buf) { bool parsed = false; - typedef struct __attribute__((packed)) { + typedef struct FURI_PACKED { uint8_t type; uint8_t comm; uint16_t access_rights; } MfDesfireFileSettingsHeader; - typedef struct __attribute__((packed)) { + typedef struct FURI_PACKED { uint32_t size : 3 * BITS_IN_BYTE; } MfDesfireFileSettingsData; - typedef struct __attribute__((packed)) { + typedef struct FURI_PACKED { uint32_t lo_limit; uint32_t hi_limit; uint32_t limited_credit_value; uint8_t limited_credit_enabled; } MfDesfireFileSettingsValue; - typedef struct __attribute__((packed)) { + typedef struct FURI_PACKED { uint32_t size : 3 * BITS_IN_BYTE; uint32_t max : 3 * BITS_IN_BYTE; uint32_t cur : 3 * BITS_IN_BYTE; } MfDesfireFileSettingsRecord; - typedef struct __attribute__((packed)) { + typedef struct FURI_PACKED { MfDesfireFileSettingsHeader header; union { MfDesfireFileSettingsData data; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h index 747f5937ad2..4786b18253c 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight.h @@ -130,7 +130,7 @@ typedef enum { MfUltralightMirrorUidCounter, } MfUltralightMirrorConf; -typedef struct __attribute__((packed)) { +typedef struct FURI_PACKED { union { uint8_t value; struct { diff --git a/lib/print/SConscript b/lib/print/SConscript index f34c8152fab..819e60bf07f 100644 --- a/lib/print/SConscript +++ b/lib/print/SConscript @@ -100,6 +100,9 @@ env.Append( SDK_HEADERS=[ File("wrappers.h"), ], + LINT_SOURCES=[ + Dir("."), + ], ) libenv = env.Clone(FW_LIB_NAME="print") diff --git a/lib/pulse_reader/SConscript b/lib/pulse_reader/SConscript index f00851a20d5..a134783798c 100644 --- a/lib/pulse_reader/SConscript +++ b/lib/pulse_reader/SConscript @@ -7,6 +7,9 @@ env.Append( SDK_HEADERS=[ File("pulse_reader.h"), ], + LINT_SOURCES=[ + Dir("."), + ], ) libenv = env.Clone(FW_LIB_NAME="pulse_reader") diff --git a/lib/qrcode/qrcode.c b/lib/qrcode/qrcode.c deleted file mode 100644 index fb5bd8a6e78..00000000000 --- a/lib/qrcode/qrcode.c +++ /dev/null @@ -1,975 +0,0 @@ -/** - * The MIT License (MIT) - * - * This library is written and maintained by Richard Moore. - * Major parts were derived from Project Nayuki's library. - * - * Copyright (c) 2017 Richard Moore (https://github.com/ricmoo/QRCode) - * Copyright (c) 2017 Project Nayuki (https://www.nayuki.io/page/qr-code-generator-library) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/** - * Special thanks to Nayuki (https://www.nayuki.io/) from which this library was - * heavily inspired and compared against. - * - * See: https://github.com/nayuki/QR-Code-generator/tree/master/cpp - */ - -#include "qrcode.h" - -#include -#include - -#pragma mark - Error Correction Lookup tables - -#if LOCK_VERSION == 0 - -static const uint16_t NUM_ERROR_CORRECTION_CODEWORDS[4][40] = { - // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level - {10, 16, 26, 36, 48, 64, 72, 88, 110, 130, 150, 176, 198, 216, - 240, 280, 308, 338, 364, 416, 442, 476, 504, 560, 588, 644, 700, 728, - 784, 812, 868, 924, 980, 1036, 1064, 1120, 1204, 1260, 1316, 1372}, // Medium - {7, 10, 15, 20, 26, 36, 40, 48, 60, 72, 80, 96, 104, 120, - 132, 144, 168, 180, 196, 224, 224, 252, 270, 300, 312, 336, 360, 390, - 420, 450, 480, 510, 540, 570, 570, 600, 630, 660, 720, 750}, // Low - {17, 28, 44, 64, 88, 112, 130, 156, 192, 224, 264, 308, 352, 384, - 432, 480, 532, 588, 650, 700, 750, 816, 900, 960, 1050, 1110, 1200, 1260, - 1350, 1440, 1530, 1620, 1710, 1800, 1890, 1980, 2100, 2220, 2310, 2430}, // High - {13, 22, 36, 52, 72, 96, 108, 132, 160, 192, 224, 260, 288, 320, - 360, 408, 448, 504, 546, 600, 644, 690, 750, 810, 870, 952, 1020, 1050, - 1140, 1200, 1290, 1350, 1440, 1530, 1590, 1680, 1770, 1860, 1950, 2040}, // Quartile -}; - -static const uint8_t NUM_ERROR_CORRECTION_BLOCKS[4][40] = { - // Version: (note that index 0 is for padding, and is set to an illegal value) - // 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level - {1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, - 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium - {1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, - 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low - {1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, - 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High - {1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, - 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile -}; - -static const uint16_t NUM_RAW_DATA_MODULES[40] = { - // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 208, - 359, - 567, - 807, - 1079, - 1383, - 1568, - 1936, - 2336, - 2768, - 3232, - 3728, - 4256, - 4651, - 5243, - 5867, - 6523, - // 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 7211, - 7931, - 8683, - 9252, - 10068, - 10916, - 11796, - 12708, - 13652, - 14628, - 15371, - 16411, - 17483, - 18587, - // 32, 33, 34, 35, 36, 37, 38, 39, 40 - 19723, - 20891, - 22091, - 23008, - 24272, - 25568, - 26896, - 28256, - 29648}; - -// @TODO: Put other LOCK_VERSIONS here -#elif LOCK_VERSION == 3 - -static const int16_t NUM_ERROR_CORRECTION_CODEWORDS[4] = {26, 15, 44, 36}; - -static const int8_t NUM_ERROR_CORRECTION_BLOCKS[4] = {1, 1, 2, 2}; - -static const uint16_t NUM_RAW_DATA_MODULES = 567; - -#else - -#error Unsupported LOCK_VERSION (add it...) - -#endif - -static int max(int a, int b) { - if(a > b) { - return a; - } - return b; -} - -/* -static int abs(int value) { - if (value < 0) { return -value; } - return value; -} -*/ - -#pragma mark - Mode testing and conversion - -static int8_t getAlphanumeric(char c) { - if(c >= '0' && c <= '9') { - return (c - '0'); - } - if(c >= 'A' && c <= 'Z') { - return (c - 'A' + 10); - } - - switch(c) { - case ' ': - return 36; - case '$': - return 37; - case '%': - return 38; - case '*': - return 39; - case '+': - return 40; - case '-': - return 41; - case '.': - return 42; - case '/': - return 43; - case ':': - return 44; - } - - return -1; -} - -static bool isAlphanumeric(const char* text, uint16_t length) { - while(length != 0) { - if(getAlphanumeric(text[--length]) == -1) { - return false; - } - } - return true; -} - -static bool isNumeric(const char* text, uint16_t length) { - while(length != 0) { - char c = text[--length]; - if(c < '0' || c > '9') { - return false; - } - } - return true; -} - -#pragma mark - Counting - -// We store the following tightly packed (less 8) in modeInfo -// <=9 <=26 <= 40 -// NUMERIC ( 10, 12, 14); -// ALPHANUMERIC ( 9, 11, 13); -// BYTE ( 8, 16, 16); -static char getModeBits(uint8_t version, uint8_t mode) { - // Note: We use 15 instead of 16; since 15 doesn't exist and we cannot store 16 (8 + 8) in 3 bits - // hex(int("".join(reversed([('00' + bin(x - 8)[2:])[-3:] for x in [10, 9, 8, 12, 11, 15, 14, 13, 15]])), 2)) - unsigned int modeInfo = 0x7bbb80a; - -#if LOCK_VERSION == 0 || LOCK_VERSION > 9 - if(version > 9) { - modeInfo >>= 9; - } -#endif - -#if LOCK_VERSION == 0 || LOCK_VERSION > 26 - if(version > 26) { - modeInfo >>= 9; - } -#endif - - char result = 8 + ((modeInfo >> (3 * mode)) & 0x07); - if(result == 15) { - result = 16; - } - - return result; -} - -#pragma mark - BitBucket - -typedef struct BitBucket { - uint32_t bitOffsetOrWidth; - uint16_t capacityBytes; - uint8_t* data; -} BitBucket; - -/* -void bb_dump(BitBucket *bitBuffer) { - printf("Buffer: "); - for (uint32_t i = 0; i < bitBuffer->capacityBytes; i++) { - printf("%02x", bitBuffer->data[i]); - if ((i % 4) == 3) { printf(" "); } - } - printf("\n"); -} -*/ - -static uint16_t bb_getGridSizeBytes(uint8_t size) { - return (((size * size) + 7) / 8); -} - -static uint16_t bb_getBufferSizeBytes(uint32_t bits) { - return ((bits + 7) / 8); -} - -static void bb_initBuffer(BitBucket* bitBuffer, uint8_t* data, int32_t capacityBytes) { - bitBuffer->bitOffsetOrWidth = 0; - bitBuffer->capacityBytes = capacityBytes; - bitBuffer->data = data; - - memset(data, 0, bitBuffer->capacityBytes); -} - -static void bb_initGrid(BitBucket* bitGrid, uint8_t* data, uint8_t size) { - bitGrid->bitOffsetOrWidth = size; - bitGrid->capacityBytes = bb_getGridSizeBytes(size); - bitGrid->data = data; - - memset(data, 0, bitGrid->capacityBytes); -} - -static void bb_appendBits(BitBucket* bitBuffer, uint32_t val, uint8_t length) { - uint32_t offset = bitBuffer->bitOffsetOrWidth; - for(int8_t i = length - 1; i >= 0; i--, offset++) { - bitBuffer->data[offset >> 3] |= ((val >> i) & 1) << (7 - (offset & 7)); - } - bitBuffer->bitOffsetOrWidth = offset; -} -/* -void bb_setBits(BitBucket *bitBuffer, uint32_t val, int offset, uint8_t length) { - for (int8_t i = length - 1; i >= 0; i--, offset++) { - bitBuffer->data[offset >> 3] |= ((val >> i) & 1) << (7 - (offset & 7)); - } -} -*/ -static void bb_setBit(BitBucket* bitGrid, uint8_t x, uint8_t y, bool on) { - uint32_t offset = y * bitGrid->bitOffsetOrWidth + x; - uint8_t mask = 1 << (7 - (offset & 0x07)); - if(on) { - bitGrid->data[offset >> 3] |= mask; - } else { - bitGrid->data[offset >> 3] &= ~mask; - } -} - -static void bb_invertBit(BitBucket* bitGrid, uint8_t x, uint8_t y, bool invert) { - uint32_t offset = y * bitGrid->bitOffsetOrWidth + x; - uint8_t mask = 1 << (7 - (offset & 0x07)); - bool on = ((bitGrid->data[offset >> 3] & (1 << (7 - (offset & 0x07)))) != 0); - if(on ^ invert) { - bitGrid->data[offset >> 3] |= mask; - } else { - bitGrid->data[offset >> 3] &= ~mask; - } -} - -static bool bb_getBit(BitBucket* bitGrid, uint8_t x, uint8_t y) { - uint32_t offset = y * bitGrid->bitOffsetOrWidth + x; - return (bitGrid->data[offset >> 3] & (1 << (7 - (offset & 0x07)))) != 0; -} - -#pragma mark - Drawing Patterns - -// XORs the data modules in this QR Code with the given mask pattern. Due to XOR's mathematical -// properties, calling applyMask(m) twice with the same value is equivalent to no change at all. -// This means it is possible to apply a mask, undo it, and try another mask. Note that a final -// well-formed QR Code symbol needs exactly one mask applied (not zero, not two, etc.). -static void applyMask(BitBucket* modules, BitBucket* isFunction, uint8_t mask) { - uint8_t size = modules->bitOffsetOrWidth; - - for(uint8_t y = 0; y < size; y++) { - for(uint8_t x = 0; x < size; x++) { - if(bb_getBit(isFunction, x, y)) { - continue; - } - - bool invert = 0; - switch(mask) { - case 0: - invert = (x + y) % 2 == 0; - break; - case 1: - invert = y % 2 == 0; - break; - case 2: - invert = x % 3 == 0; - break; - case 3: - invert = (x + y) % 3 == 0; - break; - case 4: - invert = (x / 3 + y / 2) % 2 == 0; - break; - case 5: - invert = x * y % 2 + x * y % 3 == 0; - break; - case 6: - invert = (x * y % 2 + x * y % 3) % 2 == 0; - break; - case 7: - invert = ((x + y) % 2 + x * y % 3) % 2 == 0; - break; - } - bb_invertBit(modules, x, y, invert); - } - } -} - -static void - setFunctionModule(BitBucket* modules, BitBucket* isFunction, uint8_t x, uint8_t y, bool on) { - bb_setBit(modules, x, y, on); - bb_setBit(isFunction, x, y, true); -} - -// Draws a 9*9 finder pattern including the border separator, with the center module at (x, y). -static void drawFinderPattern(BitBucket* modules, BitBucket* isFunction, uint8_t x, uint8_t y) { - uint8_t size = modules->bitOffsetOrWidth; - - for(int8_t i = -4; i <= 4; i++) { - for(int8_t j = -4; j <= 4; j++) { - uint8_t dist = max(abs(i), abs(j)); // Chebyshev/infinity norm - int16_t xx = x + j, yy = y + i; - if(0 <= xx && xx < size && 0 <= yy && yy < size) { - setFunctionModule(modules, isFunction, xx, yy, dist != 2 && dist != 4); - } - } - } -} - -// Draws a 5*5 alignment pattern, with the center module at (x, y). -static void drawAlignmentPattern(BitBucket* modules, BitBucket* isFunction, uint8_t x, uint8_t y) { - for(int8_t i = -2; i <= 2; i++) { - for(int8_t j = -2; j <= 2; j++) { - setFunctionModule(modules, isFunction, x + j, y + i, max(abs(i), abs(j)) != 1); - } - } -} - -// Draws two copies of the format bits (with its own error correction code) -// based on the given mask and this object's error correction level field. -static void drawFormatBits(BitBucket* modules, BitBucket* isFunction, uint8_t ecc, uint8_t mask) { - uint8_t size = modules->bitOffsetOrWidth; - - // Calculate error correction code and pack bits - uint32_t data = ecc << 3 | mask; // errCorrLvl is uint2, mask is uint3 - uint32_t rem = data; - for(int i = 0; i < 10; i++) { - rem = (rem << 1) ^ ((rem >> 9) * 0x537); - } - - data = data << 10 | rem; - data ^= 0x5412; // uint15 - - // Draw first copy - for(uint8_t i = 0; i <= 5; i++) { - setFunctionModule(modules, isFunction, 8, i, ((data >> i) & 1) != 0); - } - - setFunctionModule(modules, isFunction, 8, 7, ((data >> 6) & 1) != 0); - setFunctionModule(modules, isFunction, 8, 8, ((data >> 7) & 1) != 0); - setFunctionModule(modules, isFunction, 7, 8, ((data >> 8) & 1) != 0); - - for(int8_t i = 9; i < 15; i++) { - setFunctionModule(modules, isFunction, 14 - i, 8, ((data >> i) & 1) != 0); - } - - // Draw second copy - for(int8_t i = 0; i <= 7; i++) { - setFunctionModule(modules, isFunction, size - 1 - i, 8, ((data >> i) & 1) != 0); - } - - for(int8_t i = 8; i < 15; i++) { - setFunctionModule(modules, isFunction, 8, size - 15 + i, ((data >> i) & 1) != 0); - } - - setFunctionModule(modules, isFunction, 8, size - 8, true); -} - -// Draws two copies of the version bits (with its own error correction code), -// based on this object's version field (which only has an effect for 7 <= version <= 40). -static void drawVersion(BitBucket* modules, BitBucket* isFunction, uint8_t version) { - int8_t size = modules->bitOffsetOrWidth; - -#if LOCK_VERSION != 0 && LOCK_VERSION < 7 - return; - -#else - if(version < 7) { - return; - } - - // Calculate error correction code and pack bits - uint32_t rem = version; // version is uint6, in the range [7, 40] - for(uint8_t i = 0; i < 12; i++) { - rem = (rem << 1) ^ ((rem >> 11) * 0x1F25); - } - - uint32_t data = version << 12 | rem; // uint18 - - // Draw two copies - for(uint8_t i = 0; i < 18; i++) { - bool bit = ((data >> i) & 1) != 0; - uint8_t a = size - 11 + i % 3, b = i / 3; - setFunctionModule(modules, isFunction, a, b, bit); - setFunctionModule(modules, isFunction, b, a, bit); - } - -#endif -} - -static void - drawFunctionPatterns(BitBucket* modules, BitBucket* isFunction, uint8_t version, uint8_t ecc) { - uint8_t size = modules->bitOffsetOrWidth; - - // Draw the horizontal and vertical timing patterns - for(uint8_t i = 0; i < size; i++) { - setFunctionModule(modules, isFunction, 6, i, i % 2 == 0); - setFunctionModule(modules, isFunction, i, 6, i % 2 == 0); - } - - // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules) - drawFinderPattern(modules, isFunction, 3, 3); - drawFinderPattern(modules, isFunction, size - 4, 3); - drawFinderPattern(modules, isFunction, 3, size - 4); - -#if LOCK_VERSION == 0 || LOCK_VERSION > 1 - - if(version > 1) { - // Draw the numerous alignment patterns - - uint8_t alignCount = version / 7 + 2; - uint8_t step; - if(version != 32) { - step = (version * 4 + alignCount * 2 + 1) / (2 * alignCount - 2) * - 2; // ceil((size - 13) / (2*numAlign - 2)) * 2 - } else { // C-C-C-Combo breaker! - step = 26; - } - - uint8_t alignPositionIndex = alignCount - 1; - uint8_t alignPosition[alignCount]; - - alignPosition[0] = 6; - - uint8_t size = version * 4 + 17; - for(uint8_t i = 0, pos = size - 7; i < alignCount - 1; i++, pos -= step) { - alignPosition[alignPositionIndex--] = pos; - } - - for(uint8_t i = 0; i < alignCount; i++) { - for(uint8_t j = 0; j < alignCount; j++) { - if((i == 0 && j == 0) || (i == 0 && j == alignCount - 1) || - (i == alignCount - 1 && j == 0)) { - continue; // Skip the three finder corners - } else { - drawAlignmentPattern(modules, isFunction, alignPosition[i], alignPosition[j]); - } - } - } - } - -#endif - - // Draw configuration data - drawFormatBits( - modules, isFunction, ecc, 0); // Dummy mask value; overwritten later in the constructor - drawVersion(modules, isFunction, version); -} - -// Draws the given sequence of 8-bit codewords (data and error correction) onto the entire -// data area of this QR Code symbol. Function modules need to be marked off before this is called. -static void drawCodewords(BitBucket* modules, BitBucket* isFunction, BitBucket* codewords) { - uint32_t bitLength = codewords->bitOffsetOrWidth; - uint8_t* data = codewords->data; - - uint8_t size = modules->bitOffsetOrWidth; - - // Bit index into the data - uint32_t i = 0; - - // Do the funny zigzag scan - for(int16_t right = size - 1; right >= 1; - right -= 2) { // Index of right column in each column pair - if(right == 6) { - right = 5; - } - - for(uint8_t vert = 0; vert < size; vert++) { // Vertical counter - for(int j = 0; j < 2; j++) { - uint8_t x = right - j; // Actual x coordinate - bool upwards = ((right & 2) == 0) ^ (x < 6); - uint8_t y = upwards ? size - 1 - vert : vert; // Actual y coordinate - if(!bb_getBit(isFunction, x, y) && i < bitLength) { - bb_setBit(modules, x, y, ((data[i >> 3] >> (7 - (i & 7))) & 1) != 0); - i++; - } - // If there are any remainder bits (0 to 7), they are already - // set to 0/false/white when the grid of modules was initialized - } - } - } -} - -#pragma mark - Penalty Calculation - -#define PENALTY_N1 3 -#define PENALTY_N2 3 -#define PENALTY_N3 40 -#define PENALTY_N4 10 - -// Calculates and returns the penalty score based on state of this QR Code's current modules. -// This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score. -// @TODO: This can be optimized by working with the bytes instead of bits. -static uint32_t getPenaltyScore(BitBucket* modules) { - uint32_t result = 0; - - uint8_t size = modules->bitOffsetOrWidth; - - // Adjacent modules in row having same color - for(uint8_t y = 0; y < size; y++) { - bool colorX = bb_getBit(modules, 0, y); - for(uint8_t x = 1, runX = 1; x < size; x++) { - bool cx = bb_getBit(modules, x, y); - if(cx != colorX) { - colorX = cx; - runX = 1; - - } else { - runX++; - if(runX == 5) { - result += PENALTY_N1; - } else if(runX > 5) { - result++; - } - } - } - } - - // Adjacent modules in column having same color - for(uint8_t x = 0; x < size; x++) { - bool colorY = bb_getBit(modules, x, 0); - for(uint8_t y = 1, runY = 1; y < size; y++) { - bool cy = bb_getBit(modules, x, y); - if(cy != colorY) { - colorY = cy; - runY = 1; - } else { - runY++; - if(runY == 5) { - result += PENALTY_N1; - } else if(runY > 5) { - result++; - } - } - } - } - - uint16_t black = 0; - for(uint8_t y = 0; y < size; y++) { - uint16_t bitsRow = 0, bitsCol = 0; - for(uint8_t x = 0; x < size; x++) { - bool color = bb_getBit(modules, x, y); - - // 2*2 blocks of modules having same color - if(x > 0 && y > 0) { - bool colorUL = bb_getBit(modules, x - 1, y - 1); - bool colorUR = bb_getBit(modules, x, y - 1); - bool colorL = bb_getBit(modules, x - 1, y); - if(color == colorUL && color == colorUR && color == colorL) { - result += PENALTY_N2; - } - } - - // Finder-like pattern in rows and columns - bitsRow = ((bitsRow << 1) & 0x7FF) | color; - bitsCol = ((bitsCol << 1) & 0x7FF) | bb_getBit(modules, y, x); - - // Needs 11 bits accumulated - if(x >= 10) { - if(bitsRow == 0x05D || bitsRow == 0x5D0) { - result += PENALTY_N3; - } - if(bitsCol == 0x05D || bitsCol == 0x5D0) { - result += PENALTY_N3; - } - } - - // Balance of black and white modules - if(color) { - black++; - } - } - } - - // Find smallest k such that (45-5k)% <= dark/total <= (55+5k)% - uint16_t total = size * size; - for(uint16_t k = 0; black * 20 < (9 - k) * total || black * 20 > (11 + k) * total; k++) { - result += PENALTY_N4; - } - - return result; -} - -#pragma mark - Reed-Solomon Generator - -static uint8_t rs_multiply(uint8_t x, uint8_t y) { - // Russian peasant multiplication - // See: https://en.wikipedia.org/wiki/Ancient_Egyptian_multiplication - uint16_t z = 0; - for(int8_t i = 7; i >= 0; i--) { - z = (z << 1) ^ ((z >> 7) * 0x11D); - z ^= ((y >> i) & 1) * x; - } - return z; -} - -static void rs_init(uint8_t degree, uint8_t* coeff) { - memset(coeff, 0, degree); - coeff[degree - 1] = 1; - - // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}), - // drop the highest term, and store the rest of the coefficients in order of descending powers. - // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D). - uint16_t root = 1; - for(uint8_t i = 0; i < degree; i++) { - // Multiply the current product by (x - r^i) - for(uint8_t j = 0; j < degree; j++) { - coeff[j] = rs_multiply(coeff[j], root); - if(j + 1 < degree) { - coeff[j] ^= coeff[j + 1]; - } - } - root = (root << 1) ^ ((root >> 7) * 0x11D); // Multiply by 0x02 mod GF(2^8/0x11D) - } -} - -static void rs_getRemainder( - uint8_t degree, - uint8_t* coeff, - uint8_t* data, - uint8_t length, - uint8_t* result, - uint8_t stride) { - // Compute the remainder by performing polynomial division - - //for (uint8_t i = 0; i < degree; i++) { result[] = 0; } - //memset(result, 0, degree); - - for(uint8_t i = 0; i < length; i++) { - uint8_t factor = data[i] ^ result[0]; - for(uint8_t j = 1; j < degree; j++) { - result[(j - 1) * stride] = result[j * stride]; - } - result[(degree - 1) * stride] = 0; - - for(uint8_t j = 0; j < degree; j++) { - result[j * stride] ^= rs_multiply(coeff[j], factor); - } - } -} - -#pragma mark - QrCode - -static int8_t encodeDataCodewords( - BitBucket* dataCodewords, - const uint8_t* text, - uint16_t length, - uint8_t version) { - int8_t mode = MODE_BYTE; - - if(isNumeric((char*)text, length)) { - mode = MODE_NUMERIC; - bb_appendBits(dataCodewords, 1 << MODE_NUMERIC, 4); - bb_appendBits(dataCodewords, length, getModeBits(version, MODE_NUMERIC)); - - uint16_t accumData = 0; - uint8_t accumCount = 0; - for(uint16_t i = 0; i < length; i++) { - accumData = accumData * 10 + ((char)(text[i]) - '0'); - accumCount++; - if(accumCount == 3) { - bb_appendBits(dataCodewords, accumData, 10); - accumData = 0; - accumCount = 0; - } - } - - // 1 or 2 digits remaining - if(accumCount > 0) { - bb_appendBits(dataCodewords, accumData, accumCount * 3 + 1); - } - - } else if(isAlphanumeric((char*)text, length)) { - mode = MODE_ALPHANUMERIC; - bb_appendBits(dataCodewords, 1 << MODE_ALPHANUMERIC, 4); - bb_appendBits(dataCodewords, length, getModeBits(version, MODE_ALPHANUMERIC)); - - uint16_t accumData = 0; - uint8_t accumCount = 0; - for(uint16_t i = 0; i < length; i++) { - accumData = accumData * 45 + getAlphanumeric((char)(text[i])); - accumCount++; - if(accumCount == 2) { - bb_appendBits(dataCodewords, accumData, 11); - accumData = 0; - accumCount = 0; - } - } - - // 1 character remaining - if(accumCount > 0) { - bb_appendBits(dataCodewords, accumData, 6); - } - - } else { - bb_appendBits(dataCodewords, 1 << MODE_BYTE, 4); - bb_appendBits(dataCodewords, length, getModeBits(version, MODE_BYTE)); - for(uint16_t i = 0; i < length; i++) { - bb_appendBits(dataCodewords, (char)(text[i]), 8); - } - } - - //bb_setBits(dataCodewords, length, 4, getModeBits(version, mode)); - - return mode; -} - -static void performErrorCorrection(uint8_t version, uint8_t ecc, BitBucket* data) { - // See: http://www.thonky.com/qr-code-tutorial/structure-final-message - -#if LOCK_VERSION == 0 - uint8_t numBlocks = NUM_ERROR_CORRECTION_BLOCKS[ecc][version - 1]; - uint16_t totalEcc = NUM_ERROR_CORRECTION_CODEWORDS[ecc][version - 1]; - uint16_t moduleCount = NUM_RAW_DATA_MODULES[version - 1]; -#else - uint8_t numBlocks = NUM_ERROR_CORRECTION_BLOCKS[ecc]; - uint16_t totalEcc = NUM_ERROR_CORRECTION_CODEWORDS[ecc]; - uint16_t moduleCount = NUM_RAW_DATA_MODULES; -#endif - - uint8_t blockEccLen = totalEcc / numBlocks; - uint8_t numShortBlocks = numBlocks - moduleCount / 8 % numBlocks; - uint8_t shortBlockLen = moduleCount / 8 / numBlocks; - - uint8_t shortDataBlockLen = shortBlockLen - blockEccLen; - - uint8_t result[data->capacityBytes]; - memset(result, 0, sizeof(result)); - - uint8_t coeff[blockEccLen]; - rs_init(blockEccLen, coeff); - - uint16_t offset = 0; - uint8_t* dataBytes = data->data; - - // Interleave all short blocks - for(uint8_t i = 0; i < shortDataBlockLen; i++) { - uint16_t index = i; - uint8_t stride = shortDataBlockLen; - for(uint8_t blockNum = 0; blockNum < numBlocks; blockNum++) { - result[offset++] = dataBytes[index]; - -#if LOCK_VERSION == 0 || LOCK_VERSION >= 5 - if(blockNum == numShortBlocks) { - stride++; - } -#endif - index += stride; - } - } - - // Version less than 5 only have short blocks -#if LOCK_VERSION == 0 || LOCK_VERSION >= 5 - { - // Interleave long blocks - uint16_t index = shortDataBlockLen * (numShortBlocks + 1); - uint8_t stride = shortDataBlockLen; - for(uint8_t blockNum = 0; blockNum < numBlocks - numShortBlocks; blockNum++) { - result[offset++] = dataBytes[index]; - - if(blockNum == 0) { - stride++; - } - index += stride; - } - } -#endif - - // Add all ecc blocks, interleaved - uint8_t blockSize = shortDataBlockLen; - for(uint8_t blockNum = 0; blockNum < numBlocks; blockNum++) { -#if LOCK_VERSION == 0 || LOCK_VERSION >= 5 - if(blockNum == numShortBlocks) { - blockSize++; - } -#endif - rs_getRemainder( - blockEccLen, coeff, dataBytes, blockSize, &result[offset + blockNum], numBlocks); - dataBytes += blockSize; - } - - memcpy(data->data, result, data->capacityBytes); - data->bitOffsetOrWidth = moduleCount; -} - -// We store the Format bits tightly packed into a single byte (each of the 4 modes is 2 bits) -// The format bits can be determined by ECC_FORMAT_BITS >> (2 * ecc) -static const uint8_t ECC_FORMAT_BITS = (0x02 << 6) | (0x03 << 4) | (0x00 << 2) | (0x01 << 0); - -#pragma mark - Public QRCode functions - -uint16_t qrcode_getBufferSize(uint8_t version) { - return bb_getGridSizeBytes(4 * version + 17); -} - -// @TODO: Return error if data is too big. -int8_t qrcode_initBytes( - QRCode* qrcode, - uint8_t* modules, - uint8_t version, - uint8_t ecc, - uint8_t* data, - uint16_t length) { - uint8_t size = version * 4 + 17; - qrcode->version = version; - qrcode->size = size; - qrcode->ecc = ecc; - qrcode->modules = modules; - - uint8_t eccFormatBits = (ECC_FORMAT_BITS >> (2 * ecc)) & 0x03; - -#if LOCK_VERSION == 0 - uint16_t moduleCount = NUM_RAW_DATA_MODULES[version - 1]; - uint16_t dataCapacity = - moduleCount / 8 - NUM_ERROR_CORRECTION_CODEWORDS[eccFormatBits][version - 1]; -#else - version = LOCK_VERSION; - uint16_t moduleCount = NUM_RAW_DATA_MODULES; - uint16_t dataCapacity = moduleCount / 8 - NUM_ERROR_CORRECTION_CODEWORDS[eccFormatBits]; -#endif - - struct BitBucket codewords; - uint8_t codewordBytes[bb_getBufferSizeBytes(moduleCount)]; - bb_initBuffer(&codewords, codewordBytes, (int32_t)sizeof(codewordBytes)); - - // Place the data code words into the buffer - int8_t mode = encodeDataCodewords(&codewords, data, length, version); - - if(mode < 0) { - return -1; - } - qrcode->mode = mode; - - // Add terminator and pad up to a byte if applicable - uint32_t padding = (dataCapacity * 8) - codewords.bitOffsetOrWidth; - if(padding > 4) { - padding = 4; - } - bb_appendBits(&codewords, 0, padding); - bb_appendBits(&codewords, 0, (8 - codewords.bitOffsetOrWidth % 8) % 8); - - // Pad with alternate bytes until data capacity is reached - for(uint8_t padByte = 0xEC; codewords.bitOffsetOrWidth < (dataCapacity * 8); - padByte ^= 0xEC ^ 0x11) { - bb_appendBits(&codewords, padByte, 8); - } - - BitBucket modulesGrid; - bb_initGrid(&modulesGrid, modules, size); - - BitBucket isFunctionGrid; - uint8_t isFunctionGridBytes[bb_getGridSizeBytes(size)]; - bb_initGrid(&isFunctionGrid, isFunctionGridBytes, size); - - // Draw function patterns, draw all codewords, do masking - drawFunctionPatterns(&modulesGrid, &isFunctionGrid, version, eccFormatBits); - performErrorCorrection(version, eccFormatBits, &codewords); - drawCodewords(&modulesGrid, &isFunctionGrid, &codewords); - - // Find the best (lowest penalty) mask - uint8_t mask = 0; - int32_t minPenalty = INT32_MAX; - for(uint8_t i = 0; i < 8; i++) { - drawFormatBits(&modulesGrid, &isFunctionGrid, eccFormatBits, i); - applyMask(&modulesGrid, &isFunctionGrid, i); - int penalty = getPenaltyScore(&modulesGrid); - if(penalty < minPenalty) { - mask = i; - minPenalty = penalty; - } - applyMask(&modulesGrid, &isFunctionGrid, i); // Undoes the mask due to XOR - } - - qrcode->mask = mask; - - // Overwrite old format bits - drawFormatBits(&modulesGrid, &isFunctionGrid, eccFormatBits, mask); - - // Apply the final choice of mask - applyMask(&modulesGrid, &isFunctionGrid, mask); - - return 0; -} - -int8_t qrcode_initText( - QRCode* qrcode, - uint8_t* modules, - uint8_t version, - uint8_t ecc, - const char* data) { - return qrcode_initBytes(qrcode, modules, version, ecc, (uint8_t*)data, strlen(data)); -} - -bool qrcode_getModule(QRCode* qrcode, uint8_t x, uint8_t y) { - if(x < 0 || x >= qrcode->size || y < 0 || y >= qrcode->size) { - return false; - } - - uint32_t offset = y * qrcode->size + x; - return (qrcode->modules[offset >> 3] & (1 << (7 - (offset & 0x07)))) != 0; -} diff --git a/lib/qrcode/qrcode.h b/lib/qrcode/qrcode.h deleted file mode 100644 index 6d637ba04d6..00000000000 --- a/lib/qrcode/qrcode.h +++ /dev/null @@ -1,99 +0,0 @@ -/** - * The MIT License (MIT) - * - * This library is written and maintained by Richard Moore. - * Major parts were derived from Project Nayuki's library. - * - * Copyright (c) 2017 Richard Moore (https://github.com/ricmoo/QRCode) - * Copyright (c) 2017 Project Nayuki (https://www.nayuki.io/page/qr-code-generator-library) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/** - * Special thanks to Nayuki (https://www.nayuki.io/) from which this library was - * heavily inspired and compared against. - * - * See: https://github.com/nayuki/QR-Code-generator/tree/master/cpp - */ - -#ifndef __QRCODE_H_ -#define __QRCODE_H_ - -#ifndef __cplusplus -typedef unsigned char bool; -static const bool false = 0; -static const bool true = 1; -#endif - -#include - -// QR Code Format Encoding -#define MODE_NUMERIC 0 -#define MODE_ALPHANUMERIC 1 -#define MODE_BYTE 2 - -// Error Correction Code Levels -#define ECC_LOW 0 -#define ECC_MEDIUM 1 -#define ECC_QUARTILE 2 -#define ECC_HIGH 3 - -// If set to non-zero, this library can ONLY produce QR codes at that version -// This saves a lot of dynamic memory, as the codeword tables are skipped -#ifndef LOCK_VERSION -#define LOCK_VERSION 0 -#endif - -typedef struct QRCode { - uint8_t version; - uint8_t size; - uint8_t ecc; - uint8_t mode; - uint8_t mask; - uint8_t* modules; -} QRCode; - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -uint16_t qrcode_getBufferSize(uint8_t version); - -int8_t qrcode_initText( - QRCode* qrcode, - uint8_t* modules, - uint8_t version, - uint8_t ecc, - const char* data); -int8_t qrcode_initBytes( - QRCode* qrcode, - uint8_t* modules, - uint8_t version, - uint8_t ecc, - uint8_t* data, - uint16_t length); - -bool qrcode_getModule(QRCode* qrcode, uint8_t x, uint8_t y); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __QRCODE_H_ */ diff --git a/lib/signal_reader/SConscript b/lib/signal_reader/SConscript index ea731442018..386e3419d75 100644 --- a/lib/signal_reader/SConscript +++ b/lib/signal_reader/SConscript @@ -7,11 +7,14 @@ env.Append( SDK_HEADERS=[ File("signal_reader.h"), ], + LINT_SOURCES=[ + Dir("."), + ], ) libenv = env.Clone(FW_LIB_NAME="signal_reader") libenv.ApplyLibFlags() -libenv.Append(CCFLAGS=["-O3", "-funroll-loops", "-Ofast"]) +libenv.AppendUnique(CCFLAGS=["-O3", "-funroll-loops", "-Ofast"]) sources = libenv.GlobRecursive("*.c*") diff --git a/lib/subghz/SConscript b/lib/subghz/SConscript index 35850aa83e8..d0bc2a2543c 100644 --- a/lib/subghz/SConscript +++ b/lib/subghz/SConscript @@ -4,6 +4,9 @@ env.Append( CPPPATH=[ "#/lib/subghz", ], + LINT_SOURCES=[ + Dir("."), + ], SDK_HEADERS=[ File("environment.h"), File("receiver.h"), diff --git a/lib/toolbox/SConscript b/lib/toolbox/SConscript index de77f0ccf27..14f8de0646e 100644 --- a/lib/toolbox/SConscript +++ b/lib/toolbox/SConscript @@ -7,6 +7,9 @@ env.Append( CPPPATH=[ "#/lib/toolbox", ], + LINT_SOURCES=[ + Dir("."), + ], SDK_HEADERS=[ File("api_lock.h"), File("compress.h"), @@ -14,10 +17,8 @@ env.Append( File("manchester_encoder.h"), File("path.h"), File("name_generator.h"), - File("sha256.h"), File("crc32_calc.h"), File("dir_walk.h"), - File("md5.h"), File("args.h"), File("saved_struct.h"), File("version.h"), diff --git a/lib/toolbox/md5.c b/lib/toolbox/md5.c deleted file mode 100644 index a907d52e3b4..00000000000 --- a/lib/toolbox/md5.c +++ /dev/null @@ -1,299 +0,0 @@ -/******************************************************************************* -* Portions COPYRIGHT 2015 STMicroelectronics * -* Portions Copyright (C) 2006-2013, Brainspark B.V. * -*******************************************************************************/ - -/* - * RFC 1321 compliant MD5 implementation - * - * Copyright (C) 2006-2013, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/* - * The MD5 algorithm was designed by Ron Rivest in 1991. - * - * http://www.ietf.org/rfc/rfc1321.txt - */ - -/** - ****************************************************************************** - * @file md5.c - * @author MCD Application Team - * @brief This file has been modified to support the hardware Cryptographic and - * Hash processors embedded in STM32F415xx/417xx/437xx/439xx/756xx devices. - * This support is activated by defining the "USE_STM32F4XX_HW_CRYPTO" - * or "USE_STM32F7XX_HW_CRYPTO" macro in PolarSSL config.h file. - ****************************************************************************** - * @attention - * - * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); - * You may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.st.com/software_license_agreement_liberty_v2 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ****************************************************************************** - */ - -#include "md5.h" - -/* - * 32-bit integer manipulation macros (little endian) - */ -#ifndef GET_UINT32_LE -#define GET_UINT32_LE(n, b, i) \ - { \ - (n) = ((uint32_t)(b)[(i)]) | ((uint32_t)(b)[(i) + 1] << 8) | \ - ((uint32_t)(b)[(i) + 2] << 16) | ((uint32_t)(b)[(i) + 3] << 24); \ - } -#endif - -#ifndef PUT_UINT32_LE -#define PUT_UINT32_LE(n, b, i) \ - { \ - (b)[(i)] = (unsigned char)((n)); \ - (b)[(i) + 1] = (unsigned char)((n) >> 8); \ - (b)[(i) + 2] = (unsigned char)((n) >> 16); \ - (b)[(i) + 3] = (unsigned char)((n) >> 24); \ - } -#endif - -/* - * MD5 context setup - */ -void md5_starts(md5_context* ctx) { - ctx->total[0] = 0; - ctx->total[1] = 0; - - ctx->state[0] = 0x67452301; - ctx->state[1] = 0xEFCDAB89; - ctx->state[2] = 0x98BADCFE; - ctx->state[3] = 0x10325476; -} - -void md5_process(md5_context* ctx, const unsigned char data[64]) { - uint32_t X[16], A, B, C, D; - - GET_UINT32_LE(X[0], data, 0); - GET_UINT32_LE(X[1], data, 4); - GET_UINT32_LE(X[2], data, 8); - GET_UINT32_LE(X[3], data, 12); - GET_UINT32_LE(X[4], data, 16); - GET_UINT32_LE(X[5], data, 20); - GET_UINT32_LE(X[6], data, 24); - GET_UINT32_LE(X[7], data, 28); - GET_UINT32_LE(X[8], data, 32); - GET_UINT32_LE(X[9], data, 36); - GET_UINT32_LE(X[10], data, 40); - GET_UINT32_LE(X[11], data, 44); - GET_UINT32_LE(X[12], data, 48); - GET_UINT32_LE(X[13], data, 52); - GET_UINT32_LE(X[14], data, 56); - GET_UINT32_LE(X[15], data, 60); - -#define S(x, n) (((x) << (n)) | (((x)&0xFFFFFFFF) >> (32 - (n)))) - -#define P(a, b, c, d, k, s, t) \ - { \ - a += F(b, c, d) + X[k] + t; \ - a = S(a, s) + b; \ - } - - A = ctx->state[0]; - B = ctx->state[1]; - C = ctx->state[2]; - D = ctx->state[3]; - -#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) - - P(A, B, C, D, 0, 7, 0xD76AA478); - P(D, A, B, C, 1, 12, 0xE8C7B756); - P(C, D, A, B, 2, 17, 0x242070DB); - P(B, C, D, A, 3, 22, 0xC1BDCEEE); - P(A, B, C, D, 4, 7, 0xF57C0FAF); - P(D, A, B, C, 5, 12, 0x4787C62A); - P(C, D, A, B, 6, 17, 0xA8304613); - P(B, C, D, A, 7, 22, 0xFD469501); - P(A, B, C, D, 8, 7, 0x698098D8); - P(D, A, B, C, 9, 12, 0x8B44F7AF); - P(C, D, A, B, 10, 17, 0xFFFF5BB1); - P(B, C, D, A, 11, 22, 0x895CD7BE); - P(A, B, C, D, 12, 7, 0x6B901122); - P(D, A, B, C, 13, 12, 0xFD987193); - P(C, D, A, B, 14, 17, 0xA679438E); - P(B, C, D, A, 15, 22, 0x49B40821); - -#undef F - -#define F(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) - - P(A, B, C, D, 1, 5, 0xF61E2562); - P(D, A, B, C, 6, 9, 0xC040B340); - P(C, D, A, B, 11, 14, 0x265E5A51); - P(B, C, D, A, 0, 20, 0xE9B6C7AA); - P(A, B, C, D, 5, 5, 0xD62F105D); - P(D, A, B, C, 10, 9, 0x02441453); - P(C, D, A, B, 15, 14, 0xD8A1E681); - P(B, C, D, A, 4, 20, 0xE7D3FBC8); - P(A, B, C, D, 9, 5, 0x21E1CDE6); - P(D, A, B, C, 14, 9, 0xC33707D6); - P(C, D, A, B, 3, 14, 0xF4D50D87); - P(B, C, D, A, 8, 20, 0x455A14ED); - P(A, B, C, D, 13, 5, 0xA9E3E905); - P(D, A, B, C, 2, 9, 0xFCEFA3F8); - P(C, D, A, B, 7, 14, 0x676F02D9); - P(B, C, D, A, 12, 20, 0x8D2A4C8A); - -#undef F - -#define F(x, y, z) ((x) ^ (y) ^ (z)) - - P(A, B, C, D, 5, 4, 0xFFFA3942); - P(D, A, B, C, 8, 11, 0x8771F681); - P(C, D, A, B, 11, 16, 0x6D9D6122); - P(B, C, D, A, 14, 23, 0xFDE5380C); - P(A, B, C, D, 1, 4, 0xA4BEEA44); - P(D, A, B, C, 4, 11, 0x4BDECFA9); - P(C, D, A, B, 7, 16, 0xF6BB4B60); - P(B, C, D, A, 10, 23, 0xBEBFBC70); - P(A, B, C, D, 13, 4, 0x289B7EC6); - P(D, A, B, C, 0, 11, 0xEAA127FA); - P(C, D, A, B, 3, 16, 0xD4EF3085); - P(B, C, D, A, 6, 23, 0x04881D05); - P(A, B, C, D, 9, 4, 0xD9D4D039); - P(D, A, B, C, 12, 11, 0xE6DB99E5); - P(C, D, A, B, 15, 16, 0x1FA27CF8); - P(B, C, D, A, 2, 23, 0xC4AC5665); - -#undef F - -#define F(x, y, z) ((y) ^ ((x) | ~(z))) - - P(A, B, C, D, 0, 6, 0xF4292244); - P(D, A, B, C, 7, 10, 0x432AFF97); - P(C, D, A, B, 14, 15, 0xAB9423A7); - P(B, C, D, A, 5, 21, 0xFC93A039); - P(A, B, C, D, 12, 6, 0x655B59C3); - P(D, A, B, C, 3, 10, 0x8F0CCC92); - P(C, D, A, B, 10, 15, 0xFFEFF47D); - P(B, C, D, A, 1, 21, 0x85845DD1); - P(A, B, C, D, 8, 6, 0x6FA87E4F); - P(D, A, B, C, 15, 10, 0xFE2CE6E0); - P(C, D, A, B, 6, 15, 0xA3014314); - P(B, C, D, A, 13, 21, 0x4E0811A1); - P(A, B, C, D, 4, 6, 0xF7537E82); - P(D, A, B, C, 11, 10, 0xBD3AF235); - P(C, D, A, B, 2, 15, 0x2AD7D2BB); - P(B, C, D, A, 9, 21, 0xEB86D391); - -#undef F - - ctx->state[0] += A; - ctx->state[1] += B; - ctx->state[2] += C; - ctx->state[3] += D; -} - -/* - * MD5 process buffer - */ -void md5_update(md5_context* ctx, const unsigned char* input, size_t ilen) { - size_t fill; - uint32_t left; - - if(ilen <= 0) return; - - left = ctx->total[0] & 0x3F; - fill = 64 - left; - - ctx->total[0] += (uint32_t)ilen; - ctx->total[0] &= 0xFFFFFFFF; - - if(ctx->total[0] < (uint32_t)ilen) ctx->total[1]++; - - if(left && ilen >= fill) { - memcpy((void*)(ctx->buffer + left), input, fill); - md5_process(ctx, ctx->buffer); - input += fill; - ilen -= fill; - left = 0; - } - - while(ilen >= 64) { - md5_process(ctx, input); - input += 64; - ilen -= 64; - } - - if(ilen > 0) { - memcpy((void*)(ctx->buffer + left), input, ilen); - } -} - -static const unsigned char md5_padding[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - -/* - * MD5 final digest - */ -void md5_finish(md5_context* ctx, unsigned char output[16]) { - uint32_t last, padn; - uint32_t high, low; - unsigned char msglen[8]; - - high = (ctx->total[0] >> 29) | (ctx->total[1] << 3); - low = (ctx->total[0] << 3); - - PUT_UINT32_LE(low, msglen, 0); - PUT_UINT32_LE(high, msglen, 4); - - last = ctx->total[0] & 0x3F; - padn = (last < 56) ? (56 - last) : (120 - last); - - md5_update(ctx, md5_padding, padn); - md5_update(ctx, msglen, 8); - - PUT_UINT32_LE(ctx->state[0], output, 0); - PUT_UINT32_LE(ctx->state[1], output, 4); - PUT_UINT32_LE(ctx->state[2], output, 8); - PUT_UINT32_LE(ctx->state[3], output, 12); -} - -/* - * output = MD5( input buffer ) - */ -void md5(const unsigned char* input, size_t ilen, unsigned char output[16]) { - md5_context ctx; - - md5_starts(&ctx); - md5_update(&ctx, input, ilen); - md5_finish(&ctx, output); - - memset(&ctx, 0, sizeof(md5_context)); //-V597 -} diff --git a/lib/toolbox/md5.h b/lib/toolbox/md5.h deleted file mode 100644 index fe53db8d3e5..00000000000 --- a/lib/toolbox/md5.h +++ /dev/null @@ -1,83 +0,0 @@ -/** - * \file md5.h - * - * \brief MD5 message digest algorithm (hash function) - * - * Copyright (C) 2006-2013, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include - -/** - * \brief MD5 context structure - */ -typedef struct { - uint32_t total[2]; /*!< number of bytes processed */ - uint32_t state[4]; /*!< intermediate digest state */ - unsigned char buffer[64]; /*!< data block being processed */ -} md5_context; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief MD5 context setup - * - * \param ctx context to be initialized - */ -void md5_starts(md5_context* ctx); - -/** - * \brief MD5 process buffer - * - * \param ctx MD5 context - * \param input buffer holding the data - * \param ilen length of the input data - */ -void md5_update(md5_context* ctx, const unsigned char* input, size_t ilen); - -/** - * \brief MD5 final digest - * - * \param ctx MD5 context - * \param output MD5 checksum result - */ -void md5_finish(md5_context* ctx, unsigned char output[16]); - -/* Internal use */ -void md5_process(md5_context* ctx, const unsigned char data[64]); - -/** - * \brief Output = MD5( input buffer ) - * - * \param input buffer holding the data - * \param ilen length of the input data - * \param output MD5 checksum result - */ -void md5(const unsigned char* input, size_t ilen, unsigned char output[16]); - -#ifdef __cplusplus -} -#endif diff --git a/lib/toolbox/md5_calc.c b/lib/toolbox/md5_calc.c index 7f335a33f2b..59c9403e812 100644 --- a/lib/toolbox/md5_calc.c +++ b/lib/toolbox/md5_calc.c @@ -1,24 +1,38 @@ -#include "md5.h" #include "md5_calc.h" +#include +#include +#include + bool md5_calc_file(File* file, const char* path, unsigned char output[16], FS_Error* file_error) { - bool result = storage_file_open(file, path, FSAM_READ, FSOM_OPEN_EXISTING); + if(!storage_file_open(file, path, FSAM_READ, FSOM_OPEN_EXISTING)) { + if(file_error != NULL) { + *file_error = storage_file_get_error(file); + } + return false; + } - if(result) { - const size_t size_to_read = 512; - uint8_t* data = malloc(size_to_read); - md5_context* md5_ctx = malloc(sizeof(md5_context)); - - md5_starts(md5_ctx); - while(true) { - size_t read_size = storage_file_read(file, data, size_to_read); - if(read_size == 0) break; - md5_update(md5_ctx, data, read_size); + const size_t size_to_read = 512; + uint8_t* data = malloc(size_to_read); + bool result = true; + + mbedtls_md5_context* md5_ctx = malloc(sizeof(mbedtls_md5_context)); + mbedtls_md5_init(md5_ctx); + mbedtls_md5_starts(md5_ctx); + while(true) { + size_t read_size = storage_file_read(file, data, size_to_read); + if(storage_file_get_error(file) != FSE_OK) { + result = false; + break; + } + if(read_size == 0) { + break; } - md5_finish(md5_ctx, output); - free(md5_ctx); - free(data); + mbedtls_md5_update(md5_ctx, data, read_size); } + mbedtls_md5_finish(md5_ctx, output); + free(md5_ctx); + free(data); if(file_error != NULL) { *file_error = storage_file_get_error(file); diff --git a/lib/toolbox/sha256.c b/lib/toolbox/sha256.c deleted file mode 100644 index ff4984439db..00000000000 --- a/lib/toolbox/sha256.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * sha256.c -- Compute SHA-256 hash - * - * Just for little endian architecture. - * - * Code taken from: - * http://gladman.plushost.co.uk/oldsite/cryptography_technology/sha/index.php - * - * File names are sha2.c, sha2.h, brg_types.h, brg_endian.h - * in the archive sha2-07-01-07.zip. - * - * Code is modified in the style of PolarSSL API. - * - * See original copyright notice below. - */ -/* - --------------------------------------------------------------------------- - Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. - - LICENSE TERMS - - The free distribution and use of this software in both source and binary - form is allowed (with or without changes) provided that: - - 1. distributions of this source code include the above copyright - notice, this list of conditions and the following disclaimer; - - 2. distributions in binary form include the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other associated materials; - - 3. the copyright holder's name is not used to endorse products - built using this software without specific written permission. - - ALTERNATIVELY, provided that this notice is retained in full, this product - may be distributed under the terms of the GNU General Public License (GPL), - in which case the provisions of the GPL apply INSTEAD OF those given above. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and/or fitness for purpose. - --------------------------------------------------------------------------- - Issue Date: 01/08/2005 -*/ - -#include -#include -#include -#include "sha256.h" - -#define SHA256_MASK (SHA256_BLOCK_SIZE - 1) - -static void memcpy_output_bswap32(unsigned char* dst, const uint32_t* p) { - int i; - uint32_t q = 0; - - for(i = 0; i < 32; i++) { - if((i & 3) == 0) q = __builtin_bswap32(p[i >> 2]); /* bswap32 is GCC extention */ - dst[i] = q >> ((i & 3) * 8); - } -} - -#define rotr32(x, n) (((x) >> n) | ((x) << (32 - (n)))) - -#define ch(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) -#define maj(x, y, z) (((x) & (y)) | ((z) & ((x) ^ (y)))) - -/* round transforms for SHA256 compression functions */ -#define vf(n, i) v[((n) - (i)) & 7] - -#define hf(i) (p[(i)&15] += g_1(p[((i) + 14) & 15]) + p[((i) + 9) & 15] + g_0(p[((i) + 1) & 15])) - -#define v_cycle0(i) \ - p[i] = __builtin_bswap32(p[i]); \ - vf(7, i) += p[i] + k_0[i] + s_1(vf(4, i)) + ch(vf(4, i), vf(5, i), vf(6, i)); \ - vf(3, i) += vf(7, i); \ - vf(7, i) += s_0(vf(0, i)) + maj(vf(0, i), vf(1, i), vf(2, i)) - -#define v_cycle(i, j) \ - vf(7, i) += hf(i) + k_0[i + j] + s_1(vf(4, i)) + ch(vf(4, i), vf(5, i), vf(6, i)); \ - vf(3, i) += vf(7, i); \ - vf(7, i) += s_0(vf(0, i)) + maj(vf(0, i), vf(1, i), vf(2, i)) - -#define s_0(x) (rotr32((x), 2) ^ rotr32((x), 13) ^ rotr32((x), 22)) -#define s_1(x) (rotr32((x), 6) ^ rotr32((x), 11) ^ rotr32((x), 25)) -#define g_0(x) (rotr32((x), 7) ^ rotr32((x), 18) ^ ((x) >> 3)) -#define g_1(x) (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10)) -#define k_0 k256 - -static const uint32_t k256[64] = { - 0X428A2F98, 0X71374491, 0XB5C0FBCF, 0XE9B5DBA5, 0X3956C25B, 0X59F111F1, 0X923F82A4, 0XAB1C5ED5, - 0XD807AA98, 0X12835B01, 0X243185BE, 0X550C7DC3, 0X72BE5D74, 0X80DEB1FE, 0X9BDC06A7, 0XC19BF174, - 0XE49B69C1, 0XEFBE4786, 0X0FC19DC6, 0X240CA1CC, 0X2DE92C6F, 0X4A7484AA, 0X5CB0A9DC, 0X76F988DA, - 0X983E5152, 0XA831C66D, 0XB00327C8, 0XBF597FC7, 0XC6E00BF3, 0XD5A79147, 0X06CA6351, 0X14292967, - 0X27B70A85, 0X2E1B2138, 0X4D2C6DFC, 0X53380D13, 0X650A7354, 0X766A0ABB, 0X81C2C92E, 0X92722C85, - 0XA2BFE8A1, 0XA81A664B, 0XC24B8B70, 0XC76C51A3, 0XD192E819, 0XD6990624, 0XF40E3585, 0X106AA070, - 0X19A4C116, 0X1E376C08, 0X2748774C, 0X34B0BCB5, 0X391C0CB3, 0X4ED8AA4A, 0X5B9CCA4F, 0X682E6FF3, - 0X748F82EE, 0X78A5636F, 0X84C87814, 0X8CC70208, 0X90BEFFFA, 0XA4506CEB, 0XBEF9A3F7, 0XC67178F2, -}; - -void sha256_process(sha256_context* ctx) { - uint32_t i; - uint32_t* p = ctx->wbuf; - uint32_t v[8]; - - memcpy(v, ctx->state, 8 * sizeof(uint32_t)); - - v_cycle0(0); - v_cycle0(1); - v_cycle0(2); - v_cycle0(3); - v_cycle0(4); - v_cycle0(5); - v_cycle0(6); - v_cycle0(7); - v_cycle0(8); - v_cycle0(9); - v_cycle0(10); - v_cycle0(11); - v_cycle0(12); - v_cycle0(13); - v_cycle0(14); - v_cycle0(15); - - for(i = 16; i < 64; i += 16) { - v_cycle(0, i); - v_cycle(1, i); - v_cycle(2, i); - v_cycle(3, i); - v_cycle(4, i); - v_cycle(5, i); - v_cycle(6, i); - v_cycle(7, i); - v_cycle(8, i); - v_cycle(9, i); - v_cycle(10, i); - v_cycle(11, i); - v_cycle(12, i); - v_cycle(13, i); - v_cycle(14, i); - v_cycle(15, i); - } - - ctx->state[0] += v[0]; - ctx->state[1] += v[1]; - ctx->state[2] += v[2]; - ctx->state[3] += v[3]; - ctx->state[4] += v[4]; - ctx->state[5] += v[5]; - ctx->state[6] += v[6]; - ctx->state[7] += v[7]; -} - -void sha256_update(sha256_context* ctx, const unsigned char* input, unsigned int ilen) { - uint32_t left = (ctx->total[0] & SHA256_MASK); - uint32_t fill = SHA256_BLOCK_SIZE - left; - - ctx->total[0] += ilen; - if(ctx->total[0] < ilen) ctx->total[1]++; - - while(ilen >= fill) { - memcpy(((unsigned char*)ctx->wbuf) + left, input, fill); - sha256_process(ctx); - input += fill; - ilen -= fill; - left = 0; - fill = SHA256_BLOCK_SIZE; - } - - memcpy(((unsigned char*)ctx->wbuf) + left, input, ilen); -} - -void sha256_finish(sha256_context* ctx, unsigned char output[32]) { - uint32_t last = (ctx->total[0] & SHA256_MASK); - - ctx->wbuf[last >> 2] = __builtin_bswap32(ctx->wbuf[last >> 2]); - ctx->wbuf[last >> 2] &= 0xffffff80UL << (8 * (~last & 3)); - ctx->wbuf[last >> 2] |= 0x00000080UL << (8 * (~last & 3)); - ctx->wbuf[last >> 2] = __builtin_bswap32(ctx->wbuf[last >> 2]); - - if(last > SHA256_BLOCK_SIZE - 9) { - if(last < 60) ctx->wbuf[15] = 0; - sha256_process(ctx); - last = 0; - } else - last = (last >> 2) + 1; - - while(last < 14) ctx->wbuf[last++] = 0; - - ctx->wbuf[14] = __builtin_bswap32((ctx->total[0] >> 29) | (ctx->total[1] << 3)); - ctx->wbuf[15] = __builtin_bswap32(ctx->total[0] << 3); - sha256_process(ctx); - - memcpy_output_bswap32(output, ctx->state); - memset(ctx, 0, sizeof(sha256_context)); -} - -static const uint32_t initial_state[8] = { - 0x6a09e667, - 0xbb67ae85, - 0x3c6ef372, - 0xa54ff53a, - 0x510e527f, - 0x9b05688c, - 0x1f83d9ab, - 0x5be0cd19}; - -void sha256_start(sha256_context* ctx) { - ctx->total[0] = ctx->total[1] = 0; - memcpy(ctx->state, initial_state, 8 * sizeof(uint32_t)); -} - -void sha256(const unsigned char* input, unsigned int ilen, unsigned char output[32]) { - sha256_context ctx; - - sha256_start(&ctx); - sha256_update(&ctx, input, ilen); - sha256_finish(&ctx, output); -} diff --git a/lib/toolbox/sha256.h b/lib/toolbox/sha256.h deleted file mode 100644 index c544d3ebb1d..00000000000 --- a/lib/toolbox/sha256.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#define SHA256_DIGEST_SIZE 32 -#define SHA256_BLOCK_SIZE 64 - -typedef struct { - uint32_t total[2]; - uint32_t state[8]; - uint32_t wbuf[16]; -} sha256_context; - -void sha256(const unsigned char* input, unsigned int ilen, unsigned char output[32]); -void sha256_start(sha256_context* ctx); -void sha256_finish(sha256_context* ctx, unsigned char output[32]); -void sha256_update(sha256_context* ctx, const unsigned char* input, unsigned int ilen); -void sha256_process(sha256_context* ctx); - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/lib/u8g2/SConscript b/lib/u8g2/SConscript new file mode 100644 index 00000000000..dacdfbacb4b --- /dev/null +++ b/lib/u8g2/SConscript @@ -0,0 +1,20 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/u8g2", + ], + LINT_SOURCES=[ + Dir("."), + ], +) + + +libenv = env.Clone(FW_LIB_NAME="u8g2") +libenv.ApplyLibFlags() + +sources = libenv.GlobRecursive("*.c") + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/lib/update_util/SConscript b/lib/update_util/SConscript new file mode 100644 index 00000000000..c818973d978 --- /dev/null +++ b/lib/update_util/SConscript @@ -0,0 +1,16 @@ +Import("env") + +env.Append( + LINT_SOURCES=[ + Dir("."), + ], +) + +libenv = env.Clone(FW_LIB_NAME="update_util") +libenv.ApplyLibFlags() + +sources = libenv.GlobRecursive("*.c") + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/scripts/fbt_tools/fbt_apps.py b/scripts/fbt_tools/fbt_apps.py index dadf6dc0c8c..7e0aec5ea60 100644 --- a/scripts/fbt_tools/fbt_apps.py +++ b/scripts/fbt_tools/fbt_apps.py @@ -125,7 +125,6 @@ def LoadAppManifest(env, entry): app_manifest_file_path = manifest_glob[0].rfile().abspath env["APPMGR"].load_manifest(app_manifest_file_path, entry) - env.Append(PY_LINT_SOURCES=[app_manifest_file_path]) except FlipperManifestException as e: if not GetOption("silent"): warn(WarningOnByDefault, str(e)) diff --git a/scripts/fbt_tools/fbt_version.py b/scripts/fbt_tools/fbt_version.py index e64167b3dc5..0dd5d0feb91 100644 --- a/scripts/fbt_tools/fbt_version.py +++ b/scripts/fbt_tools/fbt_version.py @@ -32,9 +32,9 @@ def generate(env): "${TARGET.dir.posix}", "--dir", "${ROOT_DIR}", - "${VERSIONCOMSTR}", ] - ] + ], + "${VERSIONCOMSTR}", ), emitter=_version_emitter, ), diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 7835718defa..cd89b554af8 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,47.0,, +Version,+,48.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -77,8 +77,13 @@ Header,+,lib/libusb_stm32/inc/usb_std.h,, Header,+,lib/libusb_stm32/inc/usb_tmc.h,, Header,+,lib/libusb_stm32/inc/usbd_core.h,, Header,+,lib/mbedtls/include/mbedtls/des.h,, +Header,+,lib/mbedtls/include/mbedtls/ecdh.h,, +Header,+,lib/mbedtls/include/mbedtls/ecdsa.h,, +Header,+,lib/mbedtls/include/mbedtls/ecp.h,, +Header,+,lib/mbedtls/include/mbedtls/md.h,, +Header,+,lib/mbedtls/include/mbedtls/md5.h,, Header,+,lib/mbedtls/include/mbedtls/sha1.h,, -Header,+,lib/micro-ecc/uECC.h,, +Header,+,lib/mbedtls/include/mbedtls/sha256.h,, Header,+,lib/mlib/m-algo.h,, Header,+,lib/mlib/m-array.h,, Header,+,lib/mlib/m-bptree.h,, @@ -136,13 +141,11 @@ Header,+,lib/toolbox/float_tools.h,, Header,+,lib/toolbox/hex.h,, Header,+,lib/toolbox/manchester_decoder.h,, Header,+,lib/toolbox/manchester_encoder.h,, -Header,+,lib/toolbox/md5.h,, Header,+,lib/toolbox/name_generator.h,, Header,+,lib/toolbox/path.h,, Header,+,lib/toolbox/pretty_format.h,, Header,+,lib/toolbox/protocols/protocol_dict.h,, Header,+,lib/toolbox/saved_struct.h,, -Header,+,lib/toolbox/sha256.h,, Header,+,lib/toolbox/simple_array.h,, Header,+,lib/toolbox/stream/buffered_file_stream.h,, Header,+,lib/toolbox/stream/file_stream.h,, @@ -452,7 +455,6 @@ Function,-,_system_r,int,"_reent*, const char*" Function,-,_tempnam_r,char*,"_reent*, const char*, const char*" Function,-,_tmpfile_r,FILE*,_reent* Function,-,_tmpnam_r,char*,"_reent*, char*" -Function,-,_tzset_r,void,_reent* Function,-,_ungetc_r,int,"_reent*, int, FILE*" Function,-,_unsetenv_r,int,"_reent*, const char*" Function,-,_vasiprintf_r,int,"_reent*, char**, const char*, __gnuc_va_list" @@ -499,8 +501,6 @@ Function,+,args_read_hex_bytes,_Bool,"FuriString*, uint8_t*, size_t" Function,+,args_read_int_and_trim,_Bool,"FuriString*, int*" Function,+,args_read_probably_quoted_string_and_trim,_Bool,"FuriString*, FuriString*" Function,+,args_read_string_and_trim,_Bool,"FuriString*, FuriString*" -Function,-,asctime,char*,const tm* -Function,-,asctime_r,char*,"const tm*, char*" Function,-,asin,double,double Function,-,asinf,float,float Function,-,asinh,double,double @@ -611,7 +611,7 @@ Function,+,byte_input_get_view,View*,ByteInput* Function,+,byte_input_set_header_text,void,"ByteInput*, const char*" Function,+,byte_input_set_result_callback,void,"ByteInput*, ByteInputCallback, ByteChangedCallback, void*, uint8_t*, uint8_t" Function,-,bzero,void,"void*, size_t" -Function,-,calloc,void*,"size_t, size_t" +Function,+,calloc,void*,"size_t, size_t" Function,+,canvas_clear,void,Canvas* Function,+,canvas_commit,void,Canvas* Function,+,canvas_current_font_height,uint8_t,const Canvas* @@ -665,7 +665,6 @@ Function,+,cli_read_timeout,size_t,"Cli*, uint8_t*, size_t, uint32_t" Function,+,cli_session_close,void,Cli* Function,+,cli_session_open,void,"Cli*, void*" Function,+,cli_write,void,"Cli*, const uint8_t*, size_t" -Function,-,clock,clock_t, Function,+,composite_api_resolver_add,void,"CompositeApiResolver*, const ElfApiInterface*" Function,+,composite_api_resolver_alloc,CompositeApiResolver*, Function,+,composite_api_resolver_free,void,CompositeApiResolver* @@ -689,8 +688,6 @@ Function,-,cosl,long double,long double Function,+,crc32_calc_buffer,uint32_t,"uint32_t, const void*, size_t" Function,+,crc32_calc_file,uint32_t,"File*, const FileCrcProgressCb, void*" Function,-,ctermid,char*,char* -Function,-,ctime,char*,const time_t* -Function,-,ctime_r,char*,"const time_t*, char*" Function,-,cuserid,char*,char* Function,+,dialog_ex_alloc,DialogEx*, Function,+,dialog_ex_disable_extended_events,void,DialogEx* @@ -716,7 +713,6 @@ Function,+,dialog_message_set_icon,void,"DialogMessage*, const Icon*, uint8_t, u Function,+,dialog_message_set_text,void,"DialogMessage*, const char*, uint8_t, uint8_t, Align, Align" Function,+,dialog_message_show,DialogMessageButton,"DialogsApp*, const DialogMessage*" Function,+,dialog_message_show_storage_error,void,"DialogsApp*, const char*" -Function,-,difftime,double,"time_t, time_t" Function,+,digital_sequence_add_signal,void,"DigitalSequence*, uint8_t" Function,-,digital_sequence_alloc,DigitalSequence*,"uint32_t, const GpioPin*" Function,-,digital_sequence_clear,void,DigitalSequence* @@ -1518,8 +1514,6 @@ Function,-,getenv,char*,const char* Function,-,gets,char*,char* Function,-,getsubopt,int,"char**, char**, char**" Function,-,getw,int,FILE* -Function,-,gmtime,tm*,const time_t* -Function,-,gmtime_r,tm*,"const time_t*, tm*" Function,+,gui_add_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, void*" Function,+,gui_add_view_port,void,"Gui*, ViewPort*, GuiLayer" Function,+,gui_direct_draw_acquire,Canvas*,Gui* @@ -1637,8 +1631,6 @@ Function,+,locale_get_time_format,LocaleTimeFormat, Function,+,locale_set_date_format,void,LocaleDateFormat Function,+,locale_set_measurement_unit,void,LocaleMeasurementUnits Function,+,locale_set_time_format,void,LocaleTimeFormat -Function,-,localtime,tm*,const time_t* -Function,-,localtime_r,tm*,"const time_t*, tm*" Function,-,log,double,double Function,-,log10,double,double Function,-,log10f,float,float @@ -1682,29 +1674,167 @@ Function,-,mbedtls_des_init,void,mbedtls_des_context* Function,-,mbedtls_des_key_check_key_parity,int,const unsigned char[8] Function,-,mbedtls_des_key_check_weak,int,const unsigned char[8] Function,-,mbedtls_des_key_set_parity,void,unsigned char[8] -Function,-,mbedtls_des_self_test,int,int Function,-,mbedtls_des_setkey,void,"uint32_t[32], const unsigned char[8]" Function,-,mbedtls_des_setkey_dec,int,"mbedtls_des_context*, const unsigned char[8]" Function,-,mbedtls_des_setkey_enc,int,"mbedtls_des_context*, const unsigned char[8]" +Function,-,mbedtls_ecdh_calc_secret,int,"mbedtls_ecdh_context*, size_t*, unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_can_do,int,mbedtls_ecp_group_id +Function,-,mbedtls_ecdh_compute_shared,int,"mbedtls_ecp_group*, mbedtls_mpi*, const mbedtls_ecp_point*, const mbedtls_mpi*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_free,void,mbedtls_ecdh_context* +Function,-,mbedtls_ecdh_gen_public,int,"mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_get_params,int,"mbedtls_ecdh_context*, const mbedtls_ecp_keypair*, mbedtls_ecdh_side" +Function,-,mbedtls_ecdh_init,void,mbedtls_ecdh_context* +Function,-,mbedtls_ecdh_make_params,int,"mbedtls_ecdh_context*, size_t*, unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_make_public,int,"mbedtls_ecdh_context*, size_t*, unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_read_params,int,"mbedtls_ecdh_context*, const unsigned char**, const unsigned char*" +Function,-,mbedtls_ecdh_read_public,int,"mbedtls_ecdh_context*, const unsigned char*, size_t" +Function,-,mbedtls_ecdh_setup,int,"mbedtls_ecdh_context*, mbedtls_ecp_group_id" +Function,-,mbedtls_ecdsa_can_do,int,mbedtls_ecp_group_id +Function,-,mbedtls_ecdsa_free,void,mbedtls_ecdsa_context* +Function,-,mbedtls_ecdsa_from_keypair,int,"mbedtls_ecdsa_context*, const mbedtls_ecp_keypair*" +Function,-,mbedtls_ecdsa_genkey,int,"mbedtls_ecdsa_context*, mbedtls_ecp_group_id, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdsa_init,void,mbedtls_ecdsa_context* +Function,-,mbedtls_ecdsa_read_signature,int,"mbedtls_ecdsa_context*, const unsigned char*, size_t, const unsigned char*, size_t" +Function,-,mbedtls_ecdsa_read_signature_restartable,int,"mbedtls_ecdsa_context*, const unsigned char*, size_t, const unsigned char*, size_t, mbedtls_ecdsa_restart_ctx*" +Function,-,mbedtls_ecdsa_sign,int,"mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_mpi*, const mbedtls_mpi*, const unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdsa_sign_restartable,int,"mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_mpi*, const mbedtls_mpi*, const unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*, int (*)(void*, unsigned char*, size_t), void*, mbedtls_ecdsa_restart_ctx*" +Function,-,mbedtls_ecdsa_verify,int,"mbedtls_ecp_group*, const unsigned char*, size_t, const mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_ecdsa_verify_restartable,int,"mbedtls_ecp_group*, const unsigned char*, size_t, const mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_mpi*, mbedtls_ecdsa_restart_ctx*" +Function,-,mbedtls_ecdsa_write_signature,int,"mbedtls_ecdsa_context*, mbedtls_md_type_t, const unsigned char*, size_t, unsigned char*, size_t, size_t*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdsa_write_signature_restartable,int,"mbedtls_ecdsa_context*, mbedtls_md_type_t, const unsigned char*, size_t, unsigned char*, size_t, size_t*, int (*)(void*, unsigned char*, size_t), void*, mbedtls_ecdsa_restart_ctx*" +Function,-,mbedtls_ecp_check_privkey,int,"const mbedtls_ecp_group*, const mbedtls_mpi*" +Function,-,mbedtls_ecp_check_pub_priv,int,"const mbedtls_ecp_keypair*, const mbedtls_ecp_keypair*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_check_pubkey,int,"const mbedtls_ecp_group*, const mbedtls_ecp_point*" +Function,-,mbedtls_ecp_copy,int,"mbedtls_ecp_point*, const mbedtls_ecp_point*" +Function,-,mbedtls_ecp_curve_info_from_grp_id,const mbedtls_ecp_curve_info*,mbedtls_ecp_group_id +Function,-,mbedtls_ecp_curve_info_from_name,const mbedtls_ecp_curve_info*,const char* +Function,-,mbedtls_ecp_curve_info_from_tls_id,const mbedtls_ecp_curve_info*,uint16_t +Function,-,mbedtls_ecp_curve_list,const mbedtls_ecp_curve_info*, +Function,-,mbedtls_ecp_export,int,"const mbedtls_ecp_keypair*, mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_ecp_point*" +Function,-,mbedtls_ecp_gen_key,int,"mbedtls_ecp_group_id, mbedtls_ecp_keypair*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_gen_keypair,int,"mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_gen_keypair_base,int,"mbedtls_ecp_group*, const mbedtls_ecp_point*, mbedtls_mpi*, mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_gen_privkey,int,"const mbedtls_ecp_group*, mbedtls_mpi*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_get_type,mbedtls_ecp_curve_type,const mbedtls_ecp_group* +Function,-,mbedtls_ecp_group_copy,int,"mbedtls_ecp_group*, const mbedtls_ecp_group*" +Function,-,mbedtls_ecp_group_free,void,mbedtls_ecp_group* +Function,-,mbedtls_ecp_group_init,void,mbedtls_ecp_group* +Function,-,mbedtls_ecp_group_load,int,"mbedtls_ecp_group*, mbedtls_ecp_group_id" +Function,-,mbedtls_ecp_grp_id_list,const mbedtls_ecp_group_id*, +Function,-,mbedtls_ecp_is_zero,int,mbedtls_ecp_point* +Function,-,mbedtls_ecp_keypair_free,void,mbedtls_ecp_keypair* +Function,-,mbedtls_ecp_keypair_init,void,mbedtls_ecp_keypair* +Function,-,mbedtls_ecp_mul,int,"mbedtls_ecp_group*, mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_mul_restartable,int,"mbedtls_ecp_group*, mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*, mbedtls_ecp_restart_ctx*" +Function,-,mbedtls_ecp_muladd,int,"mbedtls_ecp_group*, mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*" +Function,-,mbedtls_ecp_muladd_restartable,int,"mbedtls_ecp_group*, mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, mbedtls_ecp_restart_ctx*" +Function,-,mbedtls_ecp_point_cmp,int,"const mbedtls_ecp_point*, const mbedtls_ecp_point*" +Function,-,mbedtls_ecp_point_free,void,mbedtls_ecp_point* +Function,-,mbedtls_ecp_point_init,void,mbedtls_ecp_point* +Function,-,mbedtls_ecp_point_read_binary,int,"const mbedtls_ecp_group*, mbedtls_ecp_point*, const unsigned char*, size_t" +Function,-,mbedtls_ecp_point_read_string,int,"mbedtls_ecp_point*, int, const char*, const char*" +Function,-,mbedtls_ecp_point_write_binary,int,"const mbedtls_ecp_group*, const mbedtls_ecp_point*, int, size_t*, unsigned char*, size_t" +Function,-,mbedtls_ecp_read_key,int,"mbedtls_ecp_group_id, mbedtls_ecp_keypair*, const unsigned char*, size_t" +Function,-,mbedtls_ecp_set_zero,int,mbedtls_ecp_point* +Function,-,mbedtls_ecp_tls_read_group,int,"mbedtls_ecp_group*, const unsigned char**, size_t" +Function,-,mbedtls_ecp_tls_read_group_id,int,"mbedtls_ecp_group_id*, const unsigned char**, size_t" +Function,-,mbedtls_ecp_tls_read_point,int,"const mbedtls_ecp_group*, mbedtls_ecp_point*, const unsigned char**, size_t" +Function,-,mbedtls_ecp_tls_write_group,int,"const mbedtls_ecp_group*, size_t*, unsigned char*, size_t" +Function,-,mbedtls_ecp_tls_write_point,int,"const mbedtls_ecp_group*, const mbedtls_ecp_point*, int, size_t*, unsigned char*, size_t" +Function,-,mbedtls_ecp_write_key,int,"mbedtls_ecp_keypair*, unsigned char*, size_t" +Function,-,mbedtls_internal_md5_process,int,"mbedtls_md5_context*, const unsigned char[64]" Function,-,mbedtls_internal_sha1_process,int,"mbedtls_sha1_context*, const unsigned char[64]" -Function,-,mbedtls_platform_gmtime_r,tm*,"const mbedtls_time_t*, tm*" +Function,-,mbedtls_internal_sha256_process,int,"mbedtls_sha256_context*, const unsigned char[64]" +Function,-,mbedtls_md,int,"const mbedtls_md_info_t*, const unsigned char*, size_t, unsigned char*" +Function,-,mbedtls_md5,int,"const unsigned char*, size_t, unsigned char[16]" +Function,-,mbedtls_md5_clone,void,"mbedtls_md5_context*, const mbedtls_md5_context*" +Function,-,mbedtls_md5_finish,int,"mbedtls_md5_context*, unsigned char[16]" +Function,-,mbedtls_md5_free,void,mbedtls_md5_context* +Function,-,mbedtls_md5_init,void,mbedtls_md5_context* +Function,-,mbedtls_md5_starts,int,mbedtls_md5_context* +Function,-,mbedtls_md5_update,int,"mbedtls_md5_context*, const unsigned char*, size_t" +Function,-,mbedtls_md_clone,int,"mbedtls_md_context_t*, const mbedtls_md_context_t*" +Function,-,mbedtls_md_finish,int,"mbedtls_md_context_t*, unsigned char*" +Function,-,mbedtls_md_free,void,mbedtls_md_context_t* +Function,-,mbedtls_md_get_name,const char*,const mbedtls_md_info_t* +Function,-,mbedtls_md_get_size,unsigned char,const mbedtls_md_info_t* +Function,-,mbedtls_md_get_type,mbedtls_md_type_t,const mbedtls_md_info_t* +Function,-,mbedtls_md_hmac,int,"const mbedtls_md_info_t*, const unsigned char*, size_t, const unsigned char*, size_t, unsigned char*" +Function,-,mbedtls_md_hmac_finish,int,"mbedtls_md_context_t*, unsigned char*" +Function,-,mbedtls_md_hmac_reset,int,mbedtls_md_context_t* +Function,-,mbedtls_md_hmac_starts,int,"mbedtls_md_context_t*, const unsigned char*, size_t" +Function,-,mbedtls_md_hmac_update,int,"mbedtls_md_context_t*, const unsigned char*, size_t" +Function,-,mbedtls_md_info_from_ctx,const mbedtls_md_info_t*,const mbedtls_md_context_t* +Function,-,mbedtls_md_info_from_string,const mbedtls_md_info_t*,const char* +Function,-,mbedtls_md_info_from_type,const mbedtls_md_info_t*,mbedtls_md_type_t +Function,-,mbedtls_md_init,void,mbedtls_md_context_t* +Function,-,mbedtls_md_list,const int*, +Function,-,mbedtls_md_setup,int,"mbedtls_md_context_t*, const mbedtls_md_info_t*, int" +Function,-,mbedtls_md_starts,int,mbedtls_md_context_t* +Function,-,mbedtls_md_update,int,"mbedtls_md_context_t*, const unsigned char*, size_t" +Function,-,mbedtls_mpi_add_abs,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_add_int,int,"mbedtls_mpi*, const mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_add_mpi,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_bitlen,size_t,const mbedtls_mpi* +Function,-,mbedtls_mpi_cmp_abs,int,"const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_cmp_int,int,"const mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_cmp_mpi,int,"const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_copy,int,"mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_div_int,int,"mbedtls_mpi*, mbedtls_mpi*, const mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_div_mpi,int,"mbedtls_mpi*, mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_exp_mod,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*, mbedtls_mpi*" +Function,-,mbedtls_mpi_fill_random,int,"mbedtls_mpi*, size_t, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_mpi_free,void,mbedtls_mpi* +Function,-,mbedtls_mpi_gcd,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_gen_prime,int,"mbedtls_mpi*, size_t, int, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_mpi_get_bit,int,"const mbedtls_mpi*, size_t" +Function,-,mbedtls_mpi_grow,int,"mbedtls_mpi*, size_t" +Function,-,mbedtls_mpi_init,void,mbedtls_mpi* +Function,-,mbedtls_mpi_inv_mod,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_is_prime_ext,int,"const mbedtls_mpi*, int, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_mpi_lsb,size_t,const mbedtls_mpi* +Function,-,mbedtls_mpi_lset,int,"mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_lt_mpi_ct,int,"const mbedtls_mpi*, const mbedtls_mpi*, unsigned*" +Function,-,mbedtls_mpi_mod_int,int,"mbedtls_mpi_uint*, const mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_mod_mpi,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_mul_int,int,"mbedtls_mpi*, const mbedtls_mpi*, mbedtls_mpi_uint" +Function,-,mbedtls_mpi_mul_mpi,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_random,int,"mbedtls_mpi*, mbedtls_mpi_sint, const mbedtls_mpi*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_mpi_read_binary,int,"mbedtls_mpi*, const unsigned char*, size_t" +Function,-,mbedtls_mpi_read_binary_le,int,"mbedtls_mpi*, const unsigned char*, size_t" +Function,-,mbedtls_mpi_read_string,int,"mbedtls_mpi*, int, const char*" +Function,-,mbedtls_mpi_safe_cond_assign,int,"mbedtls_mpi*, const mbedtls_mpi*, unsigned char" +Function,-,mbedtls_mpi_safe_cond_swap,int,"mbedtls_mpi*, mbedtls_mpi*, unsigned char" +Function,-,mbedtls_mpi_set_bit,int,"mbedtls_mpi*, size_t, unsigned char" +Function,-,mbedtls_mpi_shift_l,int,"mbedtls_mpi*, size_t" +Function,-,mbedtls_mpi_shift_r,int,"mbedtls_mpi*, size_t" +Function,-,mbedtls_mpi_shrink,int,"mbedtls_mpi*, size_t" +Function,-,mbedtls_mpi_size,size_t,const mbedtls_mpi* +Function,-,mbedtls_mpi_sub_abs,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_sub_int,int,"mbedtls_mpi*, const mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_sub_mpi,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_swap,void,"mbedtls_mpi*, mbedtls_mpi*" +Function,-,mbedtls_mpi_write_binary,int,"const mbedtls_mpi*, unsigned char*, size_t" +Function,-,mbedtls_mpi_write_binary_le,int,"const mbedtls_mpi*, unsigned char*, size_t" +Function,-,mbedtls_mpi_write_string,int,"const mbedtls_mpi*, int, char*, size_t, size_t*" Function,-,mbedtls_platform_zeroize,void,"void*, size_t" Function,-,mbedtls_sha1,int,"const unsigned char*, size_t, unsigned char[20]" Function,-,mbedtls_sha1_clone,void,"mbedtls_sha1_context*, const mbedtls_sha1_context*" Function,-,mbedtls_sha1_finish,int,"mbedtls_sha1_context*, unsigned char[20]" Function,-,mbedtls_sha1_free,void,mbedtls_sha1_context* Function,-,mbedtls_sha1_init,void,mbedtls_sha1_context* -Function,-,mbedtls_sha1_self_test,int,int Function,-,mbedtls_sha1_starts,int,mbedtls_sha1_context* Function,-,mbedtls_sha1_update,int,"mbedtls_sha1_context*, const unsigned char*, size_t" +Function,-,mbedtls_sha256,int,"const unsigned char*, size_t, unsigned char*, int" +Function,-,mbedtls_sha256_clone,void,"mbedtls_sha256_context*, const mbedtls_sha256_context*" +Function,-,mbedtls_sha256_finish,int,"mbedtls_sha256_context*, unsigned char*" +Function,-,mbedtls_sha256_free,void,mbedtls_sha256_context* +Function,-,mbedtls_sha256_init,void,mbedtls_sha256_context* +Function,-,mbedtls_sha256_starts,int,"mbedtls_sha256_context*, int" +Function,-,mbedtls_sha256_update,int,"mbedtls_sha256_context*, const unsigned char*, size_t" Function,-,mblen,int,"const char*, size_t" Function,-,mbstowcs,size_t,"wchar_t*, const char*, size_t" Function,-,mbtowc,int,"wchar_t*, const char*, size_t" -Function,+,md5,void,"const unsigned char*, size_t, unsigned char[16]" -Function,+,md5_finish,void,"md5_context*, unsigned char[16]" -Function,+,md5_process,void,"md5_context*, const unsigned char[64]" -Function,+,md5_starts,void,md5_context* -Function,+,md5_update,void,"md5_context*, const unsigned char*, size_t" Function,-,memccpy,void*,"void*, const void*, int, size_t" Function,+,memchr,void*,"const void*, int, size_t" Function,+,memcmp,int,"const void*, const void*, size_t" @@ -1737,7 +1867,6 @@ Function,-,mkostemps,int,"char*, int, int" Function,-,mkstemp,int,char* Function,-,mkstemps,int,"char*, int" Function,-,mktemp,char*,char* -Function,-,mktime,time_t,tm* Function,-,modf,double,"double, double*" Function,-,modff,float,"float, float*" Function,-,modfl,long double,"long double, long double*" @@ -2003,11 +2132,6 @@ Function,-,setkey,void,const char* Function,-,setlinebuf,int,FILE* Function,-,setstate,char*,char* Function,-,setvbuf,int,"FILE*, char*, int, size_t" -Function,+,sha256,void,"const unsigned char*, unsigned int, unsigned char[32]" -Function,+,sha256_finish,void,"sha256_context*, unsigned char[32]" -Function,+,sha256_process,void,sha256_context* -Function,+,sha256_start,void,sha256_context* -Function,+,sha256_update,void,"sha256_context*, const unsigned char*, unsigned int" Function,+,signal_reader_alloc,SignalReader*,"const GpioPin*, uint32_t" Function,+,signal_reader_free,void,SignalReader* Function,+,signal_reader_set_polarity,void,"SignalReader*, SignalReaderPolarity" @@ -2171,8 +2295,6 @@ Function,+,stream_write_vaformat,size_t,"Stream*, const char*, va_list" Function,-,strerror,char*,int Function,-,strerror_l,char*,"int, locale_t" Function,-,strerror_r,char*,"int, char*, size_t" -Function,-,strftime,size_t,"char*, size_t, const char*, const tm*" -Function,-,strftime_l,size_t,"char*, size_t, const char*, const tm*, locale_t" Function,+,string_stream_alloc,Stream*, Function,-,strlcat,size_t,"char*, const char*, size_t" Function,+,strlcpy,size_t,"char*, const char*, size_t" @@ -2187,8 +2309,6 @@ Function,-,strndup,char*,"const char*, size_t" Function,-,strnlen,size_t,"const char*, size_t" Function,-,strnstr,char*,"const char*, const char*, size_t" Function,-,strpbrk,char*,"const char*, const char*" -Function,-,strptime,char*,"const char*, const char*, tm*" -Function,-,strptime_l,char*,"const char*, const char*, tm*, locale_t" Function,+,strrchr,char*,"const char*, int" Function,-,strsep,char*,"char**, const char*" Function,-,strsignal,char*,int @@ -2263,7 +2383,6 @@ Function,+,text_input_set_validator,void,"TextInput*, TextInputValidatorCallback Function,-,tgamma,double,double Function,-,tgammaf,float,float Function,-,tgammal,long double,long double -Function,-,time,time_t,time_t* Function,-,timingsafe_bcmp,int,"const void*, const void*, size_t" Function,-,timingsafe_memcmp,int,"const void*, const void*, size_t" Function,-,tmpfile,FILE*, @@ -2277,25 +2396,6 @@ Function,-,toupper_l,int,"int, locale_t" Function,-,trunc,double,double Function,-,truncf,float,float Function,-,truncl,long double,long double -Function,-,tzset,void, -Function,-,uECC_compress,void,"const uint8_t*, uint8_t*, uECC_Curve" -Function,+,uECC_compute_public_key,int,"const uint8_t*, uint8_t*, uECC_Curve" -Function,-,uECC_curve_private_key_size,int,uECC_Curve -Function,-,uECC_curve_public_key_size,int,uECC_Curve -Function,-,uECC_decompress,void,"const uint8_t*, uint8_t*, uECC_Curve" -Function,-,uECC_get_rng,uECC_RNG_Function, -Function,-,uECC_make_key,int,"uint8_t*, uint8_t*, uECC_Curve" -Function,-,uECC_secp160r1,uECC_Curve, -Function,-,uECC_secp192r1,uECC_Curve, -Function,-,uECC_secp224r1,uECC_Curve, -Function,-,uECC_secp256k1,uECC_Curve, -Function,+,uECC_secp256r1,uECC_Curve, -Function,+,uECC_set_rng,void,uECC_RNG_Function -Function,-,uECC_shared_secret,int,"const uint8_t*, const uint8_t*, uint8_t*, uECC_Curve" -Function,+,uECC_sign,int,"const uint8_t*, const uint8_t*, unsigned, uint8_t*, uECC_Curve" -Function,-,uECC_sign_deterministic,int,"const uint8_t*, const uint8_t*, unsigned, const uECC_HashContext*, uint8_t*, uECC_Curve" -Function,-,uECC_valid_public_key,int,"const uint8_t*, uECC_Curve" -Function,-,uECC_verify,int,"const uint8_t*, const uint8_t*, unsigned, const uint8_t*, uECC_Curve" Function,+,uint8_to_hex_chars,void,"const uint8_t*, uint8_t*, int" Function,-,ungetc,int,"int, FILE*" Function,-,unsetenv,int,const char* @@ -2428,13 +2528,10 @@ Variable,-,MSIRangeTable,const uint32_t[16], Variable,-,SmpsPrescalerTable,const uint32_t[4][6], Variable,+,SystemCoreClock,uint32_t, Variable,+,_ctype_,const char[], -Variable,-,_daylight,int, Variable,+,_global_impure_ptr,_reent*, Variable,+,_impure_ptr,_reent*, Variable,-,_sys_errlist,const char*[], Variable,-,_sys_nerr,int, -Variable,-,_timezone,long, -Variable,-,_tzname,char*[2], Variable,+,cli_vcp,CliSession, Variable,+,firmware_api_interface,const ElfApiInterface*, Variable,+,furi_hal_i2c_bus_external,FuriHalI2cBus, diff --git a/targets/f18/target.json b/targets/f18/target.json index 19de9dd6156..e021a5b2296 100644 --- a/targets/f18/target.json +++ b/targets/f18/target.json @@ -18,7 +18,6 @@ "hwdrivers", "fatfs", "littlefs", - "flipperformat", "toolbox", "digital_signal", "signal_reader", @@ -28,12 +27,15 @@ "assets", "one_wire", "music_worker", - "misc", + "mbedtls", "flipper_application", - "flipperformat", "toolbox", + "u8g2", + "nanopb", + "update_util", + "heatshrink", + "flipperformat", "flipper18" - ], "excluded_sources": [ "furi_hal_infrared.c", @@ -63,4 +65,4 @@ "ibutton", "infrared" ] -} +} \ No newline at end of file diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index f31349f9c9d..45c98ae1a5f 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,47.0,, +Version,+,48.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -90,8 +90,13 @@ Header,+,lib/libusb_stm32/inc/usb_std.h,, Header,+,lib/libusb_stm32/inc/usb_tmc.h,, Header,+,lib/libusb_stm32/inc/usbd_core.h,, Header,+,lib/mbedtls/include/mbedtls/des.h,, +Header,+,lib/mbedtls/include/mbedtls/ecdh.h,, +Header,+,lib/mbedtls/include/mbedtls/ecdsa.h,, +Header,+,lib/mbedtls/include/mbedtls/ecp.h,, +Header,+,lib/mbedtls/include/mbedtls/md.h,, +Header,+,lib/mbedtls/include/mbedtls/md5.h,, Header,+,lib/mbedtls/include/mbedtls/sha1.h,, -Header,+,lib/micro-ecc/uECC.h,, +Header,+,lib/mbedtls/include/mbedtls/sha256.h,, Header,+,lib/mlib/m-algo.h,, Header,+,lib/mlib/m-array.h,, Header,+,lib/mlib/m-bptree.h,, @@ -200,13 +205,11 @@ Header,+,lib/toolbox/float_tools.h,, Header,+,lib/toolbox/hex.h,, Header,+,lib/toolbox/manchester_decoder.h,, Header,+,lib/toolbox/manchester_encoder.h,, -Header,+,lib/toolbox/md5.h,, Header,+,lib/toolbox/name_generator.h,, Header,+,lib/toolbox/path.h,, Header,+,lib/toolbox/pretty_format.h,, Header,+,lib/toolbox/protocols/protocol_dict.h,, Header,+,lib/toolbox/saved_struct.h,, -Header,+,lib/toolbox/sha256.h,, Header,+,lib/toolbox/simple_array.h,, Header,+,lib/toolbox/stream/buffered_file_stream.h,, Header,+,lib/toolbox/stream/file_stream.h,, @@ -521,7 +524,6 @@ Function,-,_system_r,int,"_reent*, const char*" Function,-,_tempnam_r,char*,"_reent*, const char*, const char*" Function,-,_tmpfile_r,FILE*,_reent* Function,-,_tmpnam_r,char*,"_reent*, char*" -Function,-,_tzset_r,void,_reent* Function,-,_ungetc_r,int,"_reent*, int, FILE*" Function,-,_unsetenv_r,int,"_reent*, const char*" Function,-,_vasiprintf_r,int,"_reent*, char**, const char*, __gnuc_va_list" @@ -568,8 +570,6 @@ Function,+,args_read_hex_bytes,_Bool,"FuriString*, uint8_t*, size_t" Function,+,args_read_int_and_trim,_Bool,"FuriString*, int*" Function,+,args_read_probably_quoted_string_and_trim,_Bool,"FuriString*, FuriString*" Function,+,args_read_string_and_trim,_Bool,"FuriString*, FuriString*" -Function,-,asctime,char*,const tm* -Function,-,asctime_r,char*,"const tm*, char*" Function,-,asin,double,double Function,-,asinf,float,float Function,-,asinh,double,double @@ -700,7 +700,7 @@ Function,+,byte_input_get_view,View*,ByteInput* Function,+,byte_input_set_header_text,void,"ByteInput*, const char*" Function,+,byte_input_set_result_callback,void,"ByteInput*, ByteInputCallback, ByteChangedCallback, void*, uint8_t*, uint8_t" Function,-,bzero,void,"void*, size_t" -Function,-,calloc,void*,"size_t, size_t" +Function,+,calloc,void*,"size_t, size_t" Function,+,canvas_clear,void,Canvas* Function,+,canvas_commit,void,Canvas* Function,+,canvas_current_font_height,uint8_t,const Canvas* @@ -754,7 +754,6 @@ Function,+,cli_read_timeout,size_t,"Cli*, uint8_t*, size_t, uint32_t" Function,+,cli_session_close,void,Cli* Function,+,cli_session_open,void,"Cli*, void*" Function,+,cli_write,void,"Cli*, const uint8_t*, size_t" -Function,-,clock,clock_t, Function,+,composite_api_resolver_add,void,"CompositeApiResolver*, const ElfApiInterface*" Function,+,composite_api_resolver_alloc,CompositeApiResolver*, Function,+,composite_api_resolver_free,void,CompositeApiResolver* @@ -778,8 +777,6 @@ Function,-,cosl,long double,long double Function,+,crc32_calc_buffer,uint32_t,"uint32_t, const void*, size_t" Function,+,crc32_calc_file,uint32_t,"File*, const FileCrcProgressCb, void*" Function,-,ctermid,char*,char* -Function,-,ctime,char*,const time_t* -Function,-,ctime_r,char*,"const time_t*, char*" Function,-,cuserid,char*,char* Function,+,dialog_ex_alloc,DialogEx*, Function,+,dialog_ex_disable_extended_events,void,DialogEx* @@ -805,7 +802,6 @@ Function,+,dialog_message_set_icon,void,"DialogMessage*, const Icon*, uint8_t, u Function,+,dialog_message_set_text,void,"DialogMessage*, const char*, uint8_t, uint8_t, Align, Align" Function,+,dialog_message_show,DialogMessageButton,"DialogsApp*, const DialogMessage*" Function,+,dialog_message_show_storage_error,void,"DialogsApp*, const char*" -Function,-,difftime,double,"time_t, time_t" Function,+,digital_sequence_add_signal,void,"DigitalSequence*, uint8_t" Function,-,digital_sequence_alloc,DigitalSequence*,"uint32_t, const GpioPin*" Function,-,digital_sequence_clear,void,DigitalSequence* @@ -1714,8 +1710,6 @@ Function,-,getenv,char*,const char* Function,-,gets,char*,char* Function,-,getsubopt,int,"char**, char**, char**" Function,-,getw,int,FILE* -Function,-,gmtime,tm*,const time_t* -Function,-,gmtime_r,tm*,"const time_t*, tm*" Function,+,gui_add_framebuffer_callback,void,"Gui*, GuiCanvasCommitCallback, void*" Function,+,gui_add_view_port,void,"Gui*, ViewPort*, GuiLayer" Function,+,gui_direct_draw_acquire,Canvas*,Gui* @@ -2036,8 +2030,6 @@ Function,+,locale_get_time_format,LocaleTimeFormat, Function,+,locale_set_date_format,void,LocaleDateFormat Function,+,locale_set_measurement_unit,void,LocaleMeasurementUnits Function,+,locale_set_time_format,void,LocaleTimeFormat -Function,-,localtime,tm*,const time_t* -Function,-,localtime_r,tm*,"const time_t*, tm*" Function,-,log,double,double Function,-,log10,double,double Function,-,log10f,float,float @@ -2081,29 +2073,167 @@ Function,-,mbedtls_des_init,void,mbedtls_des_context* Function,-,mbedtls_des_key_check_key_parity,int,const unsigned char[8] Function,-,mbedtls_des_key_check_weak,int,const unsigned char[8] Function,-,mbedtls_des_key_set_parity,void,unsigned char[8] -Function,-,mbedtls_des_self_test,int,int Function,-,mbedtls_des_setkey,void,"uint32_t[32], const unsigned char[8]" Function,-,mbedtls_des_setkey_dec,int,"mbedtls_des_context*, const unsigned char[8]" Function,-,mbedtls_des_setkey_enc,int,"mbedtls_des_context*, const unsigned char[8]" +Function,-,mbedtls_ecdh_calc_secret,int,"mbedtls_ecdh_context*, size_t*, unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_can_do,int,mbedtls_ecp_group_id +Function,-,mbedtls_ecdh_compute_shared,int,"mbedtls_ecp_group*, mbedtls_mpi*, const mbedtls_ecp_point*, const mbedtls_mpi*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_free,void,mbedtls_ecdh_context* +Function,-,mbedtls_ecdh_gen_public,int,"mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_get_params,int,"mbedtls_ecdh_context*, const mbedtls_ecp_keypair*, mbedtls_ecdh_side" +Function,-,mbedtls_ecdh_init,void,mbedtls_ecdh_context* +Function,-,mbedtls_ecdh_make_params,int,"mbedtls_ecdh_context*, size_t*, unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_make_public,int,"mbedtls_ecdh_context*, size_t*, unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdh_read_params,int,"mbedtls_ecdh_context*, const unsigned char**, const unsigned char*" +Function,-,mbedtls_ecdh_read_public,int,"mbedtls_ecdh_context*, const unsigned char*, size_t" +Function,-,mbedtls_ecdh_setup,int,"mbedtls_ecdh_context*, mbedtls_ecp_group_id" +Function,-,mbedtls_ecdsa_can_do,int,mbedtls_ecp_group_id +Function,-,mbedtls_ecdsa_free,void,mbedtls_ecdsa_context* +Function,-,mbedtls_ecdsa_from_keypair,int,"mbedtls_ecdsa_context*, const mbedtls_ecp_keypair*" +Function,-,mbedtls_ecdsa_genkey,int,"mbedtls_ecdsa_context*, mbedtls_ecp_group_id, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdsa_init,void,mbedtls_ecdsa_context* +Function,-,mbedtls_ecdsa_read_signature,int,"mbedtls_ecdsa_context*, const unsigned char*, size_t, const unsigned char*, size_t" +Function,-,mbedtls_ecdsa_read_signature_restartable,int,"mbedtls_ecdsa_context*, const unsigned char*, size_t, const unsigned char*, size_t, mbedtls_ecdsa_restart_ctx*" +Function,-,mbedtls_ecdsa_sign,int,"mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_mpi*, const mbedtls_mpi*, const unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdsa_sign_restartable,int,"mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_mpi*, const mbedtls_mpi*, const unsigned char*, size_t, int (*)(void*, unsigned char*, size_t), void*, int (*)(void*, unsigned char*, size_t), void*, mbedtls_ecdsa_restart_ctx*" +Function,-,mbedtls_ecdsa_verify,int,"mbedtls_ecp_group*, const unsigned char*, size_t, const mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_ecdsa_verify_restartable,int,"mbedtls_ecp_group*, const unsigned char*, size_t, const mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_mpi*, mbedtls_ecdsa_restart_ctx*" +Function,-,mbedtls_ecdsa_write_signature,int,"mbedtls_ecdsa_context*, mbedtls_md_type_t, const unsigned char*, size_t, unsigned char*, size_t, size_t*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecdsa_write_signature_restartable,int,"mbedtls_ecdsa_context*, mbedtls_md_type_t, const unsigned char*, size_t, unsigned char*, size_t, size_t*, int (*)(void*, unsigned char*, size_t), void*, mbedtls_ecdsa_restart_ctx*" +Function,-,mbedtls_ecp_check_privkey,int,"const mbedtls_ecp_group*, const mbedtls_mpi*" +Function,-,mbedtls_ecp_check_pub_priv,int,"const mbedtls_ecp_keypair*, const mbedtls_ecp_keypair*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_check_pubkey,int,"const mbedtls_ecp_group*, const mbedtls_ecp_point*" +Function,-,mbedtls_ecp_copy,int,"mbedtls_ecp_point*, const mbedtls_ecp_point*" +Function,-,mbedtls_ecp_curve_info_from_grp_id,const mbedtls_ecp_curve_info*,mbedtls_ecp_group_id +Function,-,mbedtls_ecp_curve_info_from_name,const mbedtls_ecp_curve_info*,const char* +Function,-,mbedtls_ecp_curve_info_from_tls_id,const mbedtls_ecp_curve_info*,uint16_t +Function,-,mbedtls_ecp_curve_list,const mbedtls_ecp_curve_info*, +Function,-,mbedtls_ecp_export,int,"const mbedtls_ecp_keypair*, mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_ecp_point*" +Function,-,mbedtls_ecp_gen_key,int,"mbedtls_ecp_group_id, mbedtls_ecp_keypair*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_gen_keypair,int,"mbedtls_ecp_group*, mbedtls_mpi*, mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_gen_keypair_base,int,"mbedtls_ecp_group*, const mbedtls_ecp_point*, mbedtls_mpi*, mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_gen_privkey,int,"const mbedtls_ecp_group*, mbedtls_mpi*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_get_type,mbedtls_ecp_curve_type,const mbedtls_ecp_group* +Function,-,mbedtls_ecp_group_copy,int,"mbedtls_ecp_group*, const mbedtls_ecp_group*" +Function,-,mbedtls_ecp_group_free,void,mbedtls_ecp_group* +Function,-,mbedtls_ecp_group_init,void,mbedtls_ecp_group* +Function,-,mbedtls_ecp_group_load,int,"mbedtls_ecp_group*, mbedtls_ecp_group_id" +Function,-,mbedtls_ecp_grp_id_list,const mbedtls_ecp_group_id*, +Function,-,mbedtls_ecp_is_zero,int,mbedtls_ecp_point* +Function,-,mbedtls_ecp_keypair_free,void,mbedtls_ecp_keypair* +Function,-,mbedtls_ecp_keypair_init,void,mbedtls_ecp_keypair* +Function,-,mbedtls_ecp_mul,int,"mbedtls_ecp_group*, mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_ecp_mul_restartable,int,"mbedtls_ecp_group*, mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, int (*)(void*, unsigned char*, size_t), void*, mbedtls_ecp_restart_ctx*" +Function,-,mbedtls_ecp_muladd,int,"mbedtls_ecp_group*, mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*" +Function,-,mbedtls_ecp_muladd_restartable,int,"mbedtls_ecp_group*, mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, const mbedtls_mpi*, const mbedtls_ecp_point*, mbedtls_ecp_restart_ctx*" +Function,-,mbedtls_ecp_point_cmp,int,"const mbedtls_ecp_point*, const mbedtls_ecp_point*" +Function,-,mbedtls_ecp_point_free,void,mbedtls_ecp_point* +Function,-,mbedtls_ecp_point_init,void,mbedtls_ecp_point* +Function,-,mbedtls_ecp_point_read_binary,int,"const mbedtls_ecp_group*, mbedtls_ecp_point*, const unsigned char*, size_t" +Function,-,mbedtls_ecp_point_read_string,int,"mbedtls_ecp_point*, int, const char*, const char*" +Function,-,mbedtls_ecp_point_write_binary,int,"const mbedtls_ecp_group*, const mbedtls_ecp_point*, int, size_t*, unsigned char*, size_t" +Function,-,mbedtls_ecp_read_key,int,"mbedtls_ecp_group_id, mbedtls_ecp_keypair*, const unsigned char*, size_t" +Function,-,mbedtls_ecp_set_zero,int,mbedtls_ecp_point* +Function,-,mbedtls_ecp_tls_read_group,int,"mbedtls_ecp_group*, const unsigned char**, size_t" +Function,-,mbedtls_ecp_tls_read_group_id,int,"mbedtls_ecp_group_id*, const unsigned char**, size_t" +Function,-,mbedtls_ecp_tls_read_point,int,"const mbedtls_ecp_group*, mbedtls_ecp_point*, const unsigned char**, size_t" +Function,-,mbedtls_ecp_tls_write_group,int,"const mbedtls_ecp_group*, size_t*, unsigned char*, size_t" +Function,-,mbedtls_ecp_tls_write_point,int,"const mbedtls_ecp_group*, const mbedtls_ecp_point*, int, size_t*, unsigned char*, size_t" +Function,-,mbedtls_ecp_write_key,int,"mbedtls_ecp_keypair*, unsigned char*, size_t" +Function,-,mbedtls_internal_md5_process,int,"mbedtls_md5_context*, const unsigned char[64]" Function,-,mbedtls_internal_sha1_process,int,"mbedtls_sha1_context*, const unsigned char[64]" -Function,-,mbedtls_platform_gmtime_r,tm*,"const mbedtls_time_t*, tm*" +Function,-,mbedtls_internal_sha256_process,int,"mbedtls_sha256_context*, const unsigned char[64]" +Function,-,mbedtls_md,int,"const mbedtls_md_info_t*, const unsigned char*, size_t, unsigned char*" +Function,-,mbedtls_md5,int,"const unsigned char*, size_t, unsigned char[16]" +Function,-,mbedtls_md5_clone,void,"mbedtls_md5_context*, const mbedtls_md5_context*" +Function,-,mbedtls_md5_finish,int,"mbedtls_md5_context*, unsigned char[16]" +Function,-,mbedtls_md5_free,void,mbedtls_md5_context* +Function,-,mbedtls_md5_init,void,mbedtls_md5_context* +Function,-,mbedtls_md5_starts,int,mbedtls_md5_context* +Function,-,mbedtls_md5_update,int,"mbedtls_md5_context*, const unsigned char*, size_t" +Function,-,mbedtls_md_clone,int,"mbedtls_md_context_t*, const mbedtls_md_context_t*" +Function,-,mbedtls_md_finish,int,"mbedtls_md_context_t*, unsigned char*" +Function,-,mbedtls_md_free,void,mbedtls_md_context_t* +Function,-,mbedtls_md_get_name,const char*,const mbedtls_md_info_t* +Function,-,mbedtls_md_get_size,unsigned char,const mbedtls_md_info_t* +Function,-,mbedtls_md_get_type,mbedtls_md_type_t,const mbedtls_md_info_t* +Function,-,mbedtls_md_hmac,int,"const mbedtls_md_info_t*, const unsigned char*, size_t, const unsigned char*, size_t, unsigned char*" +Function,-,mbedtls_md_hmac_finish,int,"mbedtls_md_context_t*, unsigned char*" +Function,-,mbedtls_md_hmac_reset,int,mbedtls_md_context_t* +Function,-,mbedtls_md_hmac_starts,int,"mbedtls_md_context_t*, const unsigned char*, size_t" +Function,-,mbedtls_md_hmac_update,int,"mbedtls_md_context_t*, const unsigned char*, size_t" +Function,-,mbedtls_md_info_from_ctx,const mbedtls_md_info_t*,const mbedtls_md_context_t* +Function,-,mbedtls_md_info_from_string,const mbedtls_md_info_t*,const char* +Function,-,mbedtls_md_info_from_type,const mbedtls_md_info_t*,mbedtls_md_type_t +Function,-,mbedtls_md_init,void,mbedtls_md_context_t* +Function,-,mbedtls_md_list,const int*, +Function,-,mbedtls_md_setup,int,"mbedtls_md_context_t*, const mbedtls_md_info_t*, int" +Function,-,mbedtls_md_starts,int,mbedtls_md_context_t* +Function,-,mbedtls_md_update,int,"mbedtls_md_context_t*, const unsigned char*, size_t" +Function,-,mbedtls_mpi_add_abs,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_add_int,int,"mbedtls_mpi*, const mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_add_mpi,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_bitlen,size_t,const mbedtls_mpi* +Function,-,mbedtls_mpi_cmp_abs,int,"const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_cmp_int,int,"const mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_cmp_mpi,int,"const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_copy,int,"mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_div_int,int,"mbedtls_mpi*, mbedtls_mpi*, const mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_div_mpi,int,"mbedtls_mpi*, mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_exp_mod,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*, mbedtls_mpi*" +Function,-,mbedtls_mpi_fill_random,int,"mbedtls_mpi*, size_t, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_mpi_free,void,mbedtls_mpi* +Function,-,mbedtls_mpi_gcd,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_gen_prime,int,"mbedtls_mpi*, size_t, int, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_mpi_get_bit,int,"const mbedtls_mpi*, size_t" +Function,-,mbedtls_mpi_grow,int,"mbedtls_mpi*, size_t" +Function,-,mbedtls_mpi_init,void,mbedtls_mpi* +Function,-,mbedtls_mpi_inv_mod,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_is_prime_ext,int,"const mbedtls_mpi*, int, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_mpi_lsb,size_t,const mbedtls_mpi* +Function,-,mbedtls_mpi_lset,int,"mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_lt_mpi_ct,int,"const mbedtls_mpi*, const mbedtls_mpi*, unsigned*" +Function,-,mbedtls_mpi_mod_int,int,"mbedtls_mpi_uint*, const mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_mod_mpi,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_mul_int,int,"mbedtls_mpi*, const mbedtls_mpi*, mbedtls_mpi_uint" +Function,-,mbedtls_mpi_mul_mpi,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_random,int,"mbedtls_mpi*, mbedtls_mpi_sint, const mbedtls_mpi*, int (*)(void*, unsigned char*, size_t), void*" +Function,-,mbedtls_mpi_read_binary,int,"mbedtls_mpi*, const unsigned char*, size_t" +Function,-,mbedtls_mpi_read_binary_le,int,"mbedtls_mpi*, const unsigned char*, size_t" +Function,-,mbedtls_mpi_read_string,int,"mbedtls_mpi*, int, const char*" +Function,-,mbedtls_mpi_safe_cond_assign,int,"mbedtls_mpi*, const mbedtls_mpi*, unsigned char" +Function,-,mbedtls_mpi_safe_cond_swap,int,"mbedtls_mpi*, mbedtls_mpi*, unsigned char" +Function,-,mbedtls_mpi_set_bit,int,"mbedtls_mpi*, size_t, unsigned char" +Function,-,mbedtls_mpi_shift_l,int,"mbedtls_mpi*, size_t" +Function,-,mbedtls_mpi_shift_r,int,"mbedtls_mpi*, size_t" +Function,-,mbedtls_mpi_shrink,int,"mbedtls_mpi*, size_t" +Function,-,mbedtls_mpi_size,size_t,const mbedtls_mpi* +Function,-,mbedtls_mpi_sub_abs,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_sub_int,int,"mbedtls_mpi*, const mbedtls_mpi*, mbedtls_mpi_sint" +Function,-,mbedtls_mpi_sub_mpi,int,"mbedtls_mpi*, const mbedtls_mpi*, const mbedtls_mpi*" +Function,-,mbedtls_mpi_swap,void,"mbedtls_mpi*, mbedtls_mpi*" +Function,-,mbedtls_mpi_write_binary,int,"const mbedtls_mpi*, unsigned char*, size_t" +Function,-,mbedtls_mpi_write_binary_le,int,"const mbedtls_mpi*, unsigned char*, size_t" +Function,-,mbedtls_mpi_write_string,int,"const mbedtls_mpi*, int, char*, size_t, size_t*" Function,-,mbedtls_platform_zeroize,void,"void*, size_t" -Function,+,mbedtls_sha1,int,"const unsigned char*, size_t, unsigned char[20]" +Function,-,mbedtls_sha1,int,"const unsigned char*, size_t, unsigned char[20]" Function,-,mbedtls_sha1_clone,void,"mbedtls_sha1_context*, const mbedtls_sha1_context*" Function,-,mbedtls_sha1_finish,int,"mbedtls_sha1_context*, unsigned char[20]" Function,-,mbedtls_sha1_free,void,mbedtls_sha1_context* Function,-,mbedtls_sha1_init,void,mbedtls_sha1_context* -Function,-,mbedtls_sha1_self_test,int,int Function,-,mbedtls_sha1_starts,int,mbedtls_sha1_context* Function,-,mbedtls_sha1_update,int,"mbedtls_sha1_context*, const unsigned char*, size_t" +Function,-,mbedtls_sha256,int,"const unsigned char*, size_t, unsigned char*, int" +Function,-,mbedtls_sha256_clone,void,"mbedtls_sha256_context*, const mbedtls_sha256_context*" +Function,-,mbedtls_sha256_finish,int,"mbedtls_sha256_context*, unsigned char*" +Function,-,mbedtls_sha256_free,void,mbedtls_sha256_context* +Function,-,mbedtls_sha256_init,void,mbedtls_sha256_context* +Function,-,mbedtls_sha256_starts,int,"mbedtls_sha256_context*, int" +Function,-,mbedtls_sha256_update,int,"mbedtls_sha256_context*, const unsigned char*, size_t" Function,-,mblen,int,"const char*, size_t" Function,-,mbstowcs,size_t,"wchar_t*, const char*, size_t" Function,-,mbtowc,int,"wchar_t*, const char*, size_t" -Function,+,md5,void,"const unsigned char*, size_t, unsigned char[16]" -Function,+,md5_finish,void,"md5_context*, unsigned char[16]" -Function,+,md5_process,void,"md5_context*, const unsigned char[64]" -Function,+,md5_starts,void,md5_context* -Function,+,md5_update,void,"md5_context*, const unsigned char*, size_t" Function,-,memccpy,void*,"void*, const void*, int, size_t" Function,+,memchr,void*,"const void*, int, size_t" Function,+,memcmp,int,"const void*, const void*, size_t" @@ -2255,7 +2385,6 @@ Function,-,mkostemps,int,"char*, int, int" Function,-,mkstemp,int,char* Function,-,mkstemps,int,"char*, int" Function,-,mktemp,char*,char* -Function,-,mktime,time_t,tm* Function,-,modf,double,"double, double*" Function,-,modff,float,"float, float*" Function,-,modfl,long double,"long double, long double*" @@ -2593,11 +2722,6 @@ Function,-,setkey,void,const char* Function,-,setlinebuf,int,FILE* Function,-,setstate,char*,char* Function,-,setvbuf,int,"FILE*, char*, int, size_t" -Function,+,sha256,void,"const unsigned char*, unsigned int, unsigned char[32]" -Function,+,sha256_finish,void,"sha256_context*, unsigned char[32]" -Function,+,sha256_process,void,sha256_context* -Function,+,sha256_start,void,sha256_context* -Function,+,sha256_update,void,"sha256_context*, const unsigned char*, unsigned int" Function,+,signal_reader_alloc,SignalReader*,"const GpioPin*, uint32_t" Function,+,signal_reader_free,void,SignalReader* Function,+,signal_reader_set_polarity,void,"SignalReader*, SignalReaderPolarity" @@ -2800,8 +2924,6 @@ Function,+,stream_write_vaformat,size_t,"Stream*, const char*, va_list" Function,-,strerror,char*,int Function,-,strerror_l,char*,"int, locale_t" Function,-,strerror_r,char*,"int, char*, size_t" -Function,-,strftime,size_t,"char*, size_t, const char*, const tm*" -Function,-,strftime_l,size_t,"char*, size_t, const char*, const tm*, locale_t" Function,+,string_stream_alloc,Stream*, Function,-,strlcat,size_t,"char*, const char*, size_t" Function,+,strlcpy,size_t,"char*, const char*, size_t" @@ -2816,8 +2938,6 @@ Function,-,strndup,char*,"const char*, size_t" Function,-,strnlen,size_t,"const char*, size_t" Function,-,strnstr,char*,"const char*, const char*, size_t" Function,-,strpbrk,char*,"const char*, const char*" -Function,-,strptime,char*,"const char*, const char*, tm*" -Function,-,strptime_l,char*,"const char*, const char*, tm*, locale_t" Function,+,strrchr,char*,"const char*, int" Function,-,strsep,char*,"char**, const char*" Function,-,strsignal,char*,int @@ -3047,7 +3167,6 @@ Function,+,text_input_set_validator,void,"TextInput*, TextInputValidatorCallback Function,-,tgamma,double,double Function,-,tgammaf,float,float Function,-,tgammal,long double,long double -Function,-,time,time_t,time_t* Function,-,timingsafe_bcmp,int,"const void*, const void*, size_t" Function,-,timingsafe_memcmp,int,"const void*, const void*, size_t" Function,-,tmpfile,FILE*, @@ -3061,25 +3180,6 @@ Function,-,toupper_l,int,"int, locale_t" Function,-,trunc,double,double Function,-,truncf,float,float Function,-,truncl,long double,long double -Function,-,tzset,void, -Function,-,uECC_compress,void,"const uint8_t*, uint8_t*, uECC_Curve" -Function,+,uECC_compute_public_key,int,"const uint8_t*, uint8_t*, uECC_Curve" -Function,-,uECC_curve_private_key_size,int,uECC_Curve -Function,-,uECC_curve_public_key_size,int,uECC_Curve -Function,-,uECC_decompress,void,"const uint8_t*, uint8_t*, uECC_Curve" -Function,-,uECC_get_rng,uECC_RNG_Function, -Function,-,uECC_make_key,int,"uint8_t*, uint8_t*, uECC_Curve" -Function,-,uECC_secp160r1,uECC_Curve, -Function,-,uECC_secp192r1,uECC_Curve, -Function,-,uECC_secp224r1,uECC_Curve, -Function,-,uECC_secp256k1,uECC_Curve, -Function,+,uECC_secp256r1,uECC_Curve, -Function,+,uECC_set_rng,void,uECC_RNG_Function -Function,-,uECC_shared_secret,int,"const uint8_t*, const uint8_t*, uint8_t*, uECC_Curve" -Function,+,uECC_sign,int,"const uint8_t*, const uint8_t*, unsigned, uint8_t*, uECC_Curve" -Function,-,uECC_sign_deterministic,int,"const uint8_t*, const uint8_t*, unsigned, const uECC_HashContext*, uint8_t*, uECC_Curve" -Function,-,uECC_valid_public_key,int,"const uint8_t*, uECC_Curve" -Function,-,uECC_verify,int,"const uint8_t*, const uint8_t*, unsigned, const uint8_t*, uECC_Curve" Function,+,uint8_to_hex_chars,void,"const uint8_t*, uint8_t*, int" Function,-,ungetc,int,"int, FILE*" Function,-,unsetenv,int,const char* @@ -3212,13 +3312,10 @@ Variable,-,MSIRangeTable,const uint32_t[16], Variable,-,SmpsPrescalerTable,const uint32_t[4][6], Variable,+,SystemCoreClock,uint32_t, Variable,+,_ctype_,const char[], -Variable,-,_daylight,int, Variable,+,_global_impure_ptr,_reent*, Variable,+,_impure_ptr,_reent*, Variable,-,_sys_errlist,const char*[], Variable,-,_sys_nerr,int, -Variable,-,_timezone,long, -Variable,-,_tzname,char*[2], Variable,+,cli_vcp,CliSession, Variable,+,firmware_api_interface,const ElfApiInterface*, Variable,+,furi_hal_i2c_bus_external,FuriHalI2cBus, diff --git a/targets/f7/furi_hal/furi_hal_usb_ccid.c b/targets/f7/furi_hal/furi_hal_usb_ccid.c index 5c35c69f884..e24713ced52 100644 --- a/targets/f7/furi_hal/furi_hal_usb_ccid.c +++ b/targets/f7/furi_hal/furi_hal_usb_ccid.c @@ -39,12 +39,12 @@ struct CcidIntfDescriptor { struct usb_ccid_descriptor ccid_desc; struct usb_endpoint_descriptor ccid_bulk_in; struct usb_endpoint_descriptor ccid_bulk_out; -} __attribute__((packed)); +} FURI_PACKED; struct CcidConfigDescriptor { struct usb_config_descriptor config; struct CcidIntfDescriptor intf_0; -} __attribute__((packed)); +} FURI_PACKED; enum CCID_Features_Auto_t { CCID_Features_Auto_None = 0x0, @@ -255,7 +255,7 @@ typedef struct ccid_bulk_message_header { uint32_t dwLength; uint8_t bSlot; uint8_t bSeq; -} __attribute__((packed)) ccid_bulk_message_header_t; +} FURI_PACKED ccid_bulk_message_header_t; uint8_t SendBuffer[sizeof(ccid_bulk_message_header_t) + CCID_DATABLOCK_SIZE]; diff --git a/targets/f7/furi_hal/furi_hal_usb_cdc.c b/targets/f7/furi_hal/furi_hal_usb_cdc.c index 4c4f727badb..e9cb51e203c 100644 --- a/targets/f7/furi_hal/furi_hal_usb_cdc.c +++ b/targets/f7/furi_hal/furi_hal_usb_cdc.c @@ -35,13 +35,13 @@ struct CdcIadDescriptor { struct CdcConfigDescriptorSingle { struct usb_config_descriptor config; struct CdcIadDescriptor iad_0; -} __attribute__((packed)); +} FURI_PACKED; struct CdcConfigDescriptorDual { struct usb_config_descriptor config; struct CdcIadDescriptor iad_0; struct CdcIadDescriptor iad_1; -} __attribute__((packed)); +} FURI_PACKED; static const struct usb_string_descriptor dev_manuf_desc = USB_STRING_DESC("Flipper Devices Inc."); diff --git a/targets/f7/furi_hal/furi_hal_usb_hid.c b/targets/f7/furi_hal/furi_hal_usb_hid.c index 334aa010264..b744e5ef72e 100644 --- a/targets/f7/furi_hal/furi_hal_usb_hid.c +++ b/targets/f7/furi_hal/furi_hal_usb_hid.c @@ -24,7 +24,7 @@ struct HidIntfDescriptor { struct HidConfigDescriptor { struct usb_config_descriptor config; struct HidIntfDescriptor intf_0; -} __attribute__((packed)); +} FURI_PACKED; enum HidReportId { ReportIdKeyboard = 1, @@ -199,7 +199,7 @@ struct HidReportMouse { int8_t x; int8_t y; int8_t wheel; -} __attribute__((packed)); +} FURI_PACKED; struct HidReportKB { uint8_t report_id; @@ -208,23 +208,23 @@ struct HidReportKB { uint8_t reserved; uint8_t btn[HID_KB_MAX_KEYS]; } boot; -} __attribute__((packed)); +} FURI_PACKED; struct HidReportConsumer { uint8_t report_id; uint16_t btn[HID_CONSUMER_MAX_KEYS]; -} __attribute__((packed)); +} FURI_PACKED; struct HidReportLED { uint8_t report_id; uint8_t led_state; -} __attribute__((packed)); +} FURI_PACKED; static struct HidReport { struct HidReportKB keyboard; struct HidReportMouse mouse; struct HidReportConsumer consumer; -} __attribute__((packed)) hid_report; +} FURI_PACKED hid_report; static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx); static void hid_deinit(usbd_device* dev); diff --git a/targets/f7/furi_hal/furi_hal_usb_u2f.c b/targets/f7/furi_hal/furi_hal_usb_u2f.c index fe711512a14..cc7e23b77e3 100644 --- a/targets/f7/furi_hal/furi_hal_usb_u2f.c +++ b/targets/f7/furi_hal/furi_hal_usb_u2f.c @@ -25,7 +25,7 @@ struct HidIadDescriptor { struct HidConfigDescriptor { struct usb_config_descriptor config; struct HidIadDescriptor iad_0; -} __attribute__((packed)); +} FURI_PACKED; /* HID report: FIDO U2F */ static const uint8_t hid_u2f_report_desc[] = { diff --git a/targets/f7/target.json b/targets/f7/target.json index 63b5cdb9276..7a816828c78 100644 --- a/targets/f7/target.json +++ b/targets/f7/target.json @@ -25,7 +25,6 @@ "fatfs", "littlefs", "subghz", - "flipperformat", "toolbox", "nfc", "digital_signal", @@ -39,12 +38,15 @@ "one_wire", "ibutton", "music_worker", - "misc", "mbedtls", "lfrfid", "flipper_application", - "flipperformat", "toolbox", + "u8g2", + "nanopb", + "update_util", + "heatshrink", + "flipperformat", "flipper7" ] } \ No newline at end of file From c1e0d02afc8131e782aa3f2e5c1bbd6f43890790 Mon Sep 17 00:00:00 2001 From: Augusto Zanellato Date: Fri, 1 Dec 2023 10:42:00 +0100 Subject: [PATCH 06/14] ST25TB poller refining + write support (#3239) * nfc: st25tb: rework async poller * nfc: st25tb: introduce sync poller * nfc: st25tb: add write support * nfc: st25tb: rewrite poller to use better states * nfc: st25tb: move to mode request state after success * nfc: st25tb: minor bug fixes * type wasn't properly set on ready event * sending NfcCustomEventPollerFailure on St25tbPollerEventTypeFailure caused poller to being freed and ultimately resulted in a thread crash Co-authored-by: Aleksandr Kutuzov --- .../helpers/protocol_support/st25tb/st25tb.c | 4 +- lib/nfc/SConscript | 1 + lib/nfc/protocols/st25tb/st25tb.c | 20 ++ lib/nfc/protocols/st25tb/st25tb.h | 5 +- lib/nfc/protocols/st25tb/st25tb_poller.c | 154 +++++++++++-- lib/nfc/protocols/st25tb/st25tb_poller.h | 40 +++- lib/nfc/protocols/st25tb/st25tb_poller_i.c | 192 +++++++++------- lib/nfc/protocols/st25tb/st25tb_poller_i.h | 33 ++- lib/nfc/protocols/st25tb/st25tb_poller_sync.c | 211 ++++++++++++++++++ lib/nfc/protocols/st25tb/st25tb_poller_sync.h | 20 ++ targets/f18/api_symbols.csv | 2 +- targets/f7/api_symbols.csv | 11 +- 12 files changed, 565 insertions(+), 128 deletions(-) create mode 100644 lib/nfc/protocols/st25tb/st25tb_poller_sync.c create mode 100644 lib/nfc/protocols/st25tb/st25tb_poller_sync.h diff --git a/applications/main/nfc/helpers/protocol_support/st25tb/st25tb.c b/applications/main/nfc/helpers/protocol_support/st25tb/st25tb.c index 32b2f477570..e22af48b34e 100644 --- a/applications/main/nfc/helpers/protocol_support/st25tb/st25tb.c +++ b/applications/main/nfc/helpers/protocol_support/st25tb/st25tb.c @@ -29,7 +29,9 @@ static NfcCommand nfc_scene_read_poller_callback_st25tb(NfcGenericEvent event, v NfcApp* instance = context; const St25tbPollerEvent* st25tb_event = event.event_data; - if(st25tb_event->type == St25tbPollerEventTypeReady) { + if(st25tb_event->type == St25tbPollerEventTypeRequestMode) { + st25tb_event->data->mode_request.mode = St25tbPollerModeRead; + } else if(st25tb_event->type == St25tbPollerEventTypeSuccess) { nfc_device_set_data( instance->nfc_device, NfcProtocolSt25tb, nfc_poller_get_data(instance->poller)); view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); diff --git a/lib/nfc/SConscript b/lib/nfc/SConscript index 21f2fb49f6a..d2cfbe2fb61 100644 --- a/lib/nfc/SConscript +++ b/lib/nfc/SConscript @@ -42,6 +42,7 @@ env.Append( File("protocols/iso14443_3a/iso14443_3a_poller_sync.h"), File("protocols/mf_ultralight/mf_ultralight_poller_sync.h"), File("protocols/mf_classic/mf_classic_poller_sync.h"), + File("protocols/st25tb/st25tb_poller_sync.h"), # Misc File("helpers/nfc_util.h"), File("helpers/iso14443_crc.h"), diff --git a/lib/nfc/protocols/st25tb/st25tb.c b/lib/nfc/protocols/st25tb/st25tb.c index d3fac7eeac8..785cf831d93 100644 --- a/lib/nfc/protocols/st25tb/st25tb.c +++ b/lib/nfc/protocols/st25tb/st25tb.c @@ -232,3 +232,23 @@ St25tbData* st25tb_get_base_data(const St25tbData* data) { UNUSED(data); furi_crash("No base data"); } + +St25tbType st25tb_get_type_from_uid(const uint8_t* uid) { + switch(uid[2] >> 2) { + case 0x0: + case 0x3: + return St25tbTypeX4k; + case 0x4: + return St25tbTypeX512; + case 0x6: + return St25tbType512Ac; + case 0x7: + return St25tbType04k; + case 0xc: + return St25tbType512At; + case 0xf: + return St25tbType02k; + default: + furi_crash("unsupported st25tb type"); + } +} diff --git a/lib/nfc/protocols/st25tb/st25tb.h b/lib/nfc/protocols/st25tb/st25tb.h index 1edb296ca12..ed02dc2b207 100644 --- a/lib/nfc/protocols/st25tb/st25tb.h +++ b/lib/nfc/protocols/st25tb/st25tb.h @@ -1,6 +1,5 @@ #pragma once -#include #include #ifdef __cplusplus @@ -27,6 +26,7 @@ typedef enum { St25tbErrorFieldOff, St25tbErrorWrongCrc, St25tbErrorTimeout, + St25tbErrorWriteFailed, } St25tbError; typedef enum { @@ -44,7 +44,6 @@ typedef struct { St25tbType type; uint32_t blocks[ST25TB_MAX_BLOCKS]; uint32_t system_otp_block; - uint8_t chip_id; } St25tbData; extern const NfcDeviceBase nfc_device_st25tb; @@ -75,6 +74,8 @@ bool st25tb_set_uid(St25tbData* data, const uint8_t* uid, size_t uid_len); St25tbData* st25tb_get_base_data(const St25tbData* data); +St25tbType st25tb_get_type_from_uid(const uint8_t* uid); + #ifdef __cplusplus } #endif diff --git a/lib/nfc/protocols/st25tb/st25tb_poller.c b/lib/nfc/protocols/st25tb/st25tb_poller.c index 2bc5dd94105..fd6dc4f09f0 100644 --- a/lib/nfc/protocols/st25tb/st25tb_poller.c +++ b/lib/nfc/protocols/st25tb/st25tb_poller.c @@ -1,13 +1,12 @@ -#include "protocols/nfc_protocol.h" -#include "protocols/st25tb/st25tb.h" +#include "st25tb_poller.h" #include "st25tb_poller_i.h" #include -#include - #define TAG "ST25TBPoller" +typedef NfcCommand (*St25tbPollerStateHandler)(St25tbPoller* instance); + const St25tbData* st25tb_poller_get_data(St25tbPoller* instance) { furi_assert(instance); furi_assert(instance->data); @@ -20,6 +19,7 @@ static St25tbPoller* st25tb_poller_alloc(Nfc* nfc) { St25tbPoller* instance = malloc(sizeof(St25tbPoller)); instance->nfc = nfc; + instance->state = St25tbPollerStateSelect; instance->tx_buffer = bit_buffer_alloc(ST25TB_POLLER_MAX_BUFFER_SIZE); instance->rx_buffer = bit_buffer_alloc(ST25TB_POLLER_MAX_BUFFER_SIZE); @@ -60,6 +60,128 @@ static void instance->context = context; } +static NfcCommand st25tb_poller_select_handler(St25tbPoller* instance) { + NfcCommand command = NfcCommandContinue; + + do { + St25tbError error = st25tb_poller_select(instance, NULL); + if(error != St25tbErrorNone) { + instance->state = St25tbPollerStateFailure; + instance->st25tb_event_data.error = error; + break; + } + + instance->st25tb_event.type = St25tbPollerEventTypeReady; + instance->st25tb_event.data->ready.type = instance->data->type; + command = instance->callback(instance->general_event, instance->context); + instance->state = St25tbPollerStateRequestMode; + } while(false); + + return command; +} + +static NfcCommand st25tb_poller_request_mode_handler(St25tbPoller* instance) { + NfcCommand command = NfcCommandContinue; + instance->st25tb_event.type = St25tbPollerEventTypeRequestMode; + command = instance->callback(instance->general_event, instance->context); + + St25tbPollerEventDataModeRequest* mode_request_data = + &instance->st25tb_event_data.mode_request; + + furi_assert(mode_request_data->mode < St25tbPollerModeNum); + + if(mode_request_data->mode == St25tbPollerModeRead) { + instance->state = St25tbPollerStateRead; + instance->poller_ctx.read.current_block = 0; + } else { + instance->state = St25tbPollerStateWrite; + instance->poller_ctx.write.block_number = + mode_request_data->params.write_params.block_number; + instance->poller_ctx.write.block_data = mode_request_data->params.write_params.block_data; + } + + return command; +} + +static NfcCommand st25tb_poller_read_handler(St25tbPoller* instance) { + St25tbError error = St25tbErrorNone; + + do { + uint8_t total_blocks = st25tb_get_block_count(instance->data->type); + uint8_t* current_block = &instance->poller_ctx.read.current_block; + if(*current_block == total_blocks) { + error = st25tb_poller_read_block( + instance, &instance->data->system_otp_block, ST25TB_SYSTEM_OTP_BLOCK); + if(error != St25tbErrorNone) { + FURI_LOG_E(TAG, "Failed to read OTP block"); + instance->state = St25tbPollerStateFailure; + instance->st25tb_event_data.error = error; + break; + } else { + instance->state = St25tbPollerStateSuccess; + break; + } + } else { + error = st25tb_poller_read_block( + instance, &instance->data->blocks[*current_block], *current_block); + if(error != St25tbErrorNone) { + FURI_LOG_E(TAG, "Failed to read block %d", *current_block); + instance->state = St25tbPollerStateFailure; + instance->st25tb_event_data.error = error; + break; + } + + *current_block += 1; + } + } while(false); + + return NfcCommandContinue; +} + +static NfcCommand st25tb_poller_write_handler(St25tbPoller* instance) { + St25tbPollerWriteContext* write_ctx = &instance->poller_ctx.write; + St25tbError error = + st25tb_poller_write_block(instance, write_ctx->block_data, write_ctx->block_number); + + if(error == St25tbErrorNone) { + instance->state = St25tbPollerStateSuccess; + } else { + instance->state = St25tbPollerStateFailure; + instance->st25tb_event_data.error = error; + } + + return NfcCommandContinue; +} + +NfcCommand st25tb_poller_success_handler(St25tbPoller* instance) { + NfcCommand command = NfcCommandContinue; + instance->st25tb_event.type = St25tbPollerEventTypeSuccess; + command = instance->callback(instance->general_event, instance->context); + furi_delay_ms(100); + instance->state = St25tbPollerStateRequestMode; + + return command; +} + +NfcCommand st25tb_poller_failure_handler(St25tbPoller* instance) { + NfcCommand command = NfcCommandContinue; + instance->st25tb_event.type = St25tbPollerEventTypeFailure; + command = instance->callback(instance->general_event, instance->context); + furi_delay_ms(100); + instance->state = St25tbPollerStateSelect; + + return command; +} + +static St25tbPollerStateHandler st25tb_poller_state_handlers[St25tbPollerStateNum] = { + [St25tbPollerStateSelect] = st25tb_poller_select_handler, + [St25tbPollerStateRequestMode] = st25tb_poller_request_mode_handler, + [St25tbPollerStateRead] = st25tb_poller_read_handler, + [St25tbPollerStateWrite] = st25tb_poller_write_handler, + [St25tbPollerStateSuccess] = st25tb_poller_success_handler, + [St25tbPollerStateFailure] = st25tb_poller_failure_handler, +}; + static NfcCommand st25tb_poller_run(NfcGenericEvent event, void* context) { furi_assert(context); furi_assert(event.protocol == NfcProtocolInvalid); @@ -69,26 +191,10 @@ static NfcCommand st25tb_poller_run(NfcGenericEvent event, void* context) { NfcEvent* nfc_event = event.event_data; NfcCommand command = NfcCommandContinue; - if(nfc_event->type == NfcEventTypePollerReady) { - if(instance->state != St25tbPollerStateActivated) { - St25tbError error = st25tb_poller_activate(instance, instance->data); + furi_assert(instance->state < St25tbPollerStateNum); - if(error == St25tbErrorNone) { - instance->st25tb_event.type = St25tbPollerEventTypeReady; - instance->st25tb_event_data.error = error; - command = instance->callback(instance->general_event, instance->context); - } else { - instance->st25tb_event.type = St25tbPollerEventTypeError; - instance->st25tb_event_data.error = error; - command = instance->callback(instance->general_event, instance->context); - // Add delay to switch context - furi_delay_ms(100); - } - } else { - instance->st25tb_event.type = St25tbPollerEventTypeReady; - instance->st25tb_event_data.error = St25tbErrorNone; - command = instance->callback(instance->general_event, instance->context); - } + if(nfc_event->type == NfcEventTypePollerReady) { + command = st25tb_poller_state_handlers[instance->state](instance); } return command; @@ -103,7 +209,7 @@ static bool st25tb_poller_detect(NfcGenericEvent event, void* context) { bool protocol_detected = false; St25tbPoller* instance = context; NfcEvent* nfc_event = event.event_data; - furi_assert(instance->state == St25tbPollerStateIdle); + furi_assert(instance->state == St25tbPollerStateSelect); if(nfc_event->type == NfcEventTypePollerReady) { St25tbError error = st25tb_poller_initiate(instance, NULL); diff --git a/lib/nfc/protocols/st25tb/st25tb_poller.h b/lib/nfc/protocols/st25tb/st25tb_poller.h index d3b85e30665..87687b7eba9 100644 --- a/lib/nfc/protocols/st25tb/st25tb_poller.h +++ b/lib/nfc/protocols/st25tb/st25tb_poller.h @@ -3,8 +3,6 @@ #include "st25tb.h" #include -#include - #ifdef __cplusplus extern "C" { #endif @@ -12,11 +10,40 @@ extern "C" { typedef struct St25tbPoller St25tbPoller; typedef enum { - St25tbPollerEventTypeError, St25tbPollerEventTypeReady, + St25tbPollerEventTypeRequestMode, + St25tbPollerEventTypeFailure, + St25tbPollerEventTypeSuccess, } St25tbPollerEventType; typedef struct { + St25tbType type; +} St25tbPollerReadyData; + +typedef enum { + St25tbPollerModeRead, + St25tbPollerModeWrite, + + St25tbPollerModeNum, +} St25tbPollerMode; + +typedef struct { + uint8_t block_number; + uint32_t block_data; +} St25tbPollerEventDataModeRequestWriteParams; + +typedef union { + St25tbPollerEventDataModeRequestWriteParams write_params; +} St25tbPollerEventDataModeRequestParams; + +typedef struct { + St25tbPollerMode mode; + St25tbPollerEventDataModeRequestParams params; +} St25tbPollerEventDataModeRequest; + +typedef union { + St25tbPollerReadyData ready; + St25tbPollerEventDataModeRequest mode_request; St25tbError error; } St25tbPollerEventData; @@ -31,15 +58,18 @@ St25tbError st25tb_poller_send_frame( BitBuffer* rx_buffer, uint32_t fwt); -St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id); +St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id_ptr); -St25tbError st25tb_poller_activate(St25tbPoller* instance, St25tbData* data); +St25tbError st25tb_poller_select(St25tbPoller* instance, uint8_t* chip_id_ptr); St25tbError st25tb_poller_get_uid(St25tbPoller* instance, uint8_t* uid); St25tbError st25tb_poller_read_block(St25tbPoller* instance, uint32_t* block, uint8_t block_number); +St25tbError + st25tb_poller_write_block(St25tbPoller* instance, uint32_t block, uint8_t block_number); + St25tbError st25tb_poller_halt(St25tbPoller* instance); #ifdef __cplusplus diff --git a/lib/nfc/protocols/st25tb/st25tb_poller_i.c b/lib/nfc/protocols/st25tb/st25tb_poller_i.c index 76c9a8b1fa0..adb8626a30f 100644 --- a/lib/nfc/protocols/st25tb/st25tb_poller_i.c +++ b/lib/nfc/protocols/st25tb/st25tb_poller_i.c @@ -1,8 +1,5 @@ #include "st25tb_poller_i.h" -#include "bit_buffer.h" -#include "core/core_defines.h" -#include "protocols/st25tb/st25tb.h" #include #define TAG "ST25TBPoller" @@ -18,17 +15,7 @@ static St25tbError st25tb_poller_process_error(NfcError error) { } } -static St25tbError st25tb_poller_prepare_trx(St25tbPoller* instance) { - furi_assert(instance); - - if(instance->state == St25tbPollerStateIdle) { - return st25tb_poller_activate(instance, NULL); - } - - return St25tbErrorNone; -} - -static St25tbError st25tb_poller_frame_exchange( +St25tbError st25tb_poller_send_frame( St25tbPoller* instance, const BitBuffer* tx_buffer, BitBuffer* rx_buffer, @@ -48,7 +35,7 @@ static St25tbError st25tb_poller_frame_exchange( NfcError error = nfc_poller_trx(instance->nfc, instance->tx_buffer, instance->rx_buffer, fwt); if(error != NfcErrorNone) { - FURI_LOG_D(TAG, "error during trx: %d", error); + FURI_LOG_T(TAG, "error during trx: %d", error); ret = st25tb_poller_process_error(error); break; } @@ -65,32 +52,11 @@ static St25tbError st25tb_poller_frame_exchange( return ret; } -St25tbType st25tb_get_type_from_uid(const uint8_t uid[ST25TB_UID_SIZE]) { - switch(uid[2] >> 2) { - case 0x0: - case 0x3: - return St25tbTypeX4k; - case 0x4: - return St25tbTypeX512; - case 0x6: - return St25tbType512Ac; - case 0x7: - return St25tbType04k; - case 0xc: - return St25tbType512At; - case 0xf: - return St25tbType02k; - default: - furi_crash("unsupported st25tb type"); - } -} - -St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id) { +St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id_ptr) { // Send Initiate() furi_assert(instance); furi_assert(instance->nfc); - instance->state = St25tbPollerStateInitiateInProgress; bit_buffer_reset(instance->tx_buffer); bit_buffer_reset(instance->rx_buffer); bit_buffer_append_byte(instance->tx_buffer, 0x06); @@ -98,77 +64,90 @@ St25tbError st25tb_poller_initiate(St25tbPoller* instance, uint8_t* chip_id) { St25tbError ret; do { - ret = st25tb_poller_frame_exchange( + ret = st25tb_poller_send_frame( instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); if(ret != St25tbErrorNone) { break; } if(bit_buffer_get_size_bytes(instance->rx_buffer) != 1) { - FURI_LOG_D(TAG, "Unexpected Initiate response size"); + FURI_LOG_E(TAG, "Unexpected Initiate response size"); ret = St25tbErrorCommunication; break; } - if(chip_id) { - *chip_id = bit_buffer_get_byte(instance->rx_buffer, 0); + uint8_t chip_id = bit_buffer_get_byte(instance->rx_buffer, 0); + FURI_LOG_D(TAG, "Got chip_id=0x%02X", chip_id); + if(chip_id_ptr) { + *chip_id_ptr = bit_buffer_get_byte(instance->rx_buffer, 0); } } while(false); return ret; } -St25tbError st25tb_poller_activate(St25tbPoller* instance, St25tbData* data) { +St25tbError st25tb_poller_select(St25tbPoller* instance, uint8_t* chip_id_ptr) { furi_assert(instance); furi_assert(instance->nfc); - st25tb_reset(data); - St25tbError ret; do { - ret = st25tb_poller_initiate(instance, &data->chip_id); - if(ret != St25tbErrorNone) { - break; - } + uint8_t chip_id; - instance->state = St25tbPollerStateActivationInProgress; + if(chip_id_ptr != NULL) { + chip_id = *chip_id_ptr; + } else { + ret = st25tb_poller_initiate(instance, &chip_id); + if(ret != St25tbErrorNone) { + break; + } + } bit_buffer_reset(instance->tx_buffer); bit_buffer_reset(instance->rx_buffer); // Send Select(Chip_ID), let's just assume that collisions won't ever happen :D bit_buffer_append_byte(instance->tx_buffer, 0x0E); - bit_buffer_append_byte(instance->tx_buffer, data->chip_id); + bit_buffer_append_byte(instance->tx_buffer, chip_id); - ret = st25tb_poller_frame_exchange( + ret = st25tb_poller_send_frame( instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); if(ret != St25tbErrorNone) { - instance->state = St25tbPollerStateActivationFailed; break; } if(bit_buffer_get_size_bytes(instance->rx_buffer) != 1) { - FURI_LOG_D(TAG, "Unexpected Select response size"); - instance->state = St25tbPollerStateActivationFailed; + FURI_LOG_E(TAG, "Unexpected Select response size"); ret = St25tbErrorCommunication; break; } - if(bit_buffer_get_byte(instance->rx_buffer, 0) != data->chip_id) { - FURI_LOG_D(TAG, "ChipID mismatch"); - instance->state = St25tbPollerStateActivationFailed; + if(bit_buffer_get_byte(instance->rx_buffer, 0) != chip_id) { + FURI_LOG_E(TAG, "ChipID mismatch"); ret = St25tbErrorColResFailed; break; } - instance->state = St25tbPollerStateActivated; - ret = st25tb_poller_get_uid(instance, data->uid); + ret = st25tb_poller_get_uid(instance, instance->data->uid); if(ret != St25tbErrorNone) { - instance->state = St25tbPollerStateActivationFailed; break; } - data->type = st25tb_get_type_from_uid(data->uid); + instance->data->type = st25tb_get_type_from_uid(instance->data->uid); + } while(false); + + return ret; +} + +St25tbError st25tb_poller_read(St25tbPoller* instance, St25tbData* data) { + furi_assert(instance); + furi_assert(instance->nfc); + + St25tbError ret; + + memcpy(data, instance->data, sizeof(St25tbData)); + + do { bool read_blocks = true; for(uint8_t i = 0; i < st25tb_get_block_count(data->type); i++) { ret = st25tb_poller_read_block(instance, &data->blocks[i], i); @@ -181,6 +160,9 @@ St25tbError st25tb_poller_activate(St25tbPoller* instance, St25tbData* data) { break; } ret = st25tb_poller_read_block(instance, &data->system_otp_block, ST25TB_SYSTEM_OTP_BLOCK); + if(ret != St25tbErrorNone) { + break; + } } while(false); return ret; @@ -198,15 +180,14 @@ St25tbError st25tb_poller_get_uid(St25tbPoller* instance, uint8_t* uid) { bit_buffer_append_byte(instance->tx_buffer, 0x0B); - ret = st25tb_poller_frame_exchange( + ret = st25tb_poller_send_frame( instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); if(ret != St25tbErrorNone) { break; } if(bit_buffer_get_size_bytes(instance->rx_buffer) != ST25TB_UID_SIZE) { - FURI_LOG_D(TAG, "Unexpected Get_UID() response size"); - instance->state = St25tbPollerStateActivationFailed; + FURI_LOG_E(TAG, "Unexpected Get_UID() response size"); ret = St25tbErrorCommunication; break; } @@ -215,6 +196,17 @@ St25tbError st25tb_poller_get_uid(St25tbPoller* instance, uint8_t* uid) { FURI_SWAP(uid[1], uid[6]); FURI_SWAP(uid[2], uid[5]); FURI_SWAP(uid[3], uid[4]); + FURI_LOG_I( + TAG, + "Got tag with uid: %02X %02X %02X %02X %02X %02X %02X %02X", + uid[0], + uid[1], + uid[2], + uid[3], + uid[4], + uid[5], + uid[6], + uid[7]); } while(false); return ret; } @@ -227,7 +219,7 @@ St25tbError furi_assert( (block_number <= st25tb_get_block_count(instance->data->type)) || block_number == ST25TB_SYSTEM_OTP_BLOCK); - FURI_LOG_D(TAG, "reading block %d", block_number); + FURI_LOG_T(TAG, "reading block %d", block_number); bit_buffer_reset(instance->tx_buffer); bit_buffer_reset(instance->rx_buffer); @@ -236,60 +228,88 @@ St25tbError bit_buffer_append_byte(instance->tx_buffer, block_number); St25tbError ret; do { - ret = st25tb_poller_frame_exchange( + ret = st25tb_poller_send_frame( instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); if(ret != St25tbErrorNone) { break; } if(bit_buffer_get_size_bytes(instance->rx_buffer) != ST25TB_BLOCK_SIZE) { - FURI_LOG_D(TAG, "Unexpected Read_block(Addr) response size"); + FURI_LOG_E(TAG, "Unexpected Read_block(Addr) response size"); ret = St25tbErrorCommunication; break; } bit_buffer_write_bytes(instance->rx_buffer, block, ST25TB_BLOCK_SIZE); - FURI_LOG_D(TAG, "read result: %08lX", *block); + FURI_LOG_D(TAG, "Read_block(%d) result: %08lX", block_number, *block); } while(false); return ret; } -St25tbError st25tb_poller_halt(St25tbPoller* instance) { +St25tbError + st25tb_poller_write_block(St25tbPoller* instance, uint32_t block, uint8_t block_number) { furi_assert(instance); - + furi_assert(instance->nfc); + furi_assert( + (block_number <= st25tb_get_block_count(instance->data->type)) || + block_number == ST25TB_SYSTEM_OTP_BLOCK); + FURI_LOG_T(TAG, "writing block %d", block_number); bit_buffer_reset(instance->tx_buffer); - bit_buffer_reset(instance->rx_buffer); - - // Send Completion() - bit_buffer_append_byte(instance->tx_buffer, 0x0F); + // Send Write_block(Addr, Data) + bit_buffer_append_byte(instance->tx_buffer, 0x09); + bit_buffer_append_byte(instance->tx_buffer, block_number); + bit_buffer_append_bytes(instance->tx_buffer, (uint8_t*)&block, ST25TB_BLOCK_SIZE); St25tbError ret; - do { - ret = st25tb_poller_frame_exchange( + ret = st25tb_poller_send_frame( instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); - if(ret != St25tbErrorTimeout) { + if(ret != St25tbErrorTimeout) { // tag doesn't ack writes so timeout are expected. break; } - instance->state = St25tbPollerStateIdle; + furi_delay_ms(7); // 7ms is the max programming time as per datasheet + + uint32_t block_check; + ret = st25tb_poller_read_block(instance, &block_check, block_number); + if(ret != St25tbErrorNone) { + FURI_LOG_E(TAG, "write verification failed: read error"); + break; + } + if(block_check != block) { + FURI_LOG_E( + TAG, + "write verification failed: wrote %08lX but read back %08lX", + block, + block_check); + ret = St25tbErrorWriteFailed; + break; + } + FURI_LOG_D(TAG, "wrote %08lX to block %d", block, block_number); } while(false); return ret; } -St25tbError st25tb_poller_send_frame( - St25tbPoller* instance, - const BitBuffer* tx_buffer, - BitBuffer* rx_buffer, - uint32_t fwt) { +St25tbError st25tb_poller_halt(St25tbPoller* instance) { + furi_assert(instance); + + bit_buffer_reset(instance->tx_buffer); + bit_buffer_reset(instance->rx_buffer); + + // Send Completion() + bit_buffer_append_byte(instance->tx_buffer, 0x0F); + St25tbError ret; do { - ret = st25tb_poller_prepare_trx(instance); - if(ret != St25tbErrorNone) break; + ret = st25tb_poller_send_frame( + instance, instance->tx_buffer, instance->rx_buffer, ST25TB_FDT_FC); + if(ret != St25tbErrorTimeout) { + break; + } - ret = st25tb_poller_frame_exchange(instance, tx_buffer, rx_buffer, fwt); + instance->state = St25tbPollerStateSelect; } while(false); return ret; diff --git a/lib/nfc/protocols/st25tb/st25tb_poller_i.h b/lib/nfc/protocols/st25tb/st25tb_poller_i.h index 27218d7b44a..e16feb7812c 100644 --- a/lib/nfc/protocols/st25tb/st25tb_poller_i.h +++ b/lib/nfc/protocols/st25tb/st25tb_poller_i.h @@ -1,8 +1,9 @@ #pragma once -#include "protocols/st25tb/st25tb.h" #include "st25tb_poller.h" +#include + #ifdef __cplusplus extern "C" { #endif @@ -10,14 +11,30 @@ extern "C" { #define ST25TB_POLLER_MAX_BUFFER_SIZE (16U) typedef enum { - St25tbPollerStateIdle, - St25tbPollerStateInitiateInProgress, - St25tbPollerStateInitiateFailed, - St25tbPollerStateActivationInProgress, - St25tbPollerStateActivationFailed, - St25tbPollerStateActivated, + St25tbPollerStateSelect, + St25tbPollerStateRequestMode, + St25tbPollerStateRead, + St25tbPollerStateWrite, + St25tbPollerStateSuccess, + St25tbPollerStateFailure, + + St25tbPollerStateNum, } St25tbPollerState; +typedef struct { + uint8_t current_block; +} St25tbPollerReadContext; + +typedef struct { + uint8_t block_number; + uint32_t block_data; +} St25tbPollerWriteContext; + +typedef union { + St25tbPollerReadContext read; + St25tbPollerWriteContext write; +} St25tbPollerContext; + struct St25tbPoller { Nfc* nfc; St25tbPollerState state; @@ -25,6 +42,8 @@ struct St25tbPoller { BitBuffer* tx_buffer; BitBuffer* rx_buffer; + St25tbPollerContext poller_ctx; + NfcGenericEvent general_event; St25tbPollerEvent st25tb_event; St25tbPollerEventData st25tb_event_data; diff --git a/lib/nfc/protocols/st25tb/st25tb_poller_sync.c b/lib/nfc/protocols/st25tb/st25tb_poller_sync.c new file mode 100644 index 00000000000..3cd0b379290 --- /dev/null +++ b/lib/nfc/protocols/st25tb/st25tb_poller_sync.c @@ -0,0 +1,211 @@ +#include "st25tb_poller_sync.h" +#include "st25tb_poller_i.h" + +#define ST25TB_POLLER_FLAG_COMMAND_COMPLETE (1UL << 0) + +typedef enum { + St25tbPollerCmdTypeDetectType, + St25tbPollerCmdTypeReadBlock, + St25tbPollerCmdTypeWriteBlock, + + St25tbPollerCmdTypeNum, +} St25tbPollerCmdType; + +typedef struct { + St25tbType* type; +} St25tbPollerCmdDetectTypeData; + +typedef struct { + St25tbData* data; +} St25tbPollerCmdReadData; + +typedef struct { + uint8_t block_num; + uint32_t* block; +} St25tbPollerCmdReadBlockData; + +typedef struct { + uint8_t block_num; + uint32_t block; +} St25tbPollerCmdWriteBlockData; + +typedef union { + St25tbPollerCmdDetectTypeData detect_type; + St25tbPollerCmdReadData read; + St25tbPollerCmdReadBlockData read_block; + St25tbPollerCmdWriteBlockData write_block; +} St25tbPollerCmdData; + +typedef struct { + FuriThreadId thread_id; + St25tbError error; + St25tbPollerCmdType cmd_type; + St25tbPollerCmdData cmd_data; +} St25tbPollerSyncContext; + +typedef St25tbError (*St25tbPollerCmdHandler)(St25tbPoller* poller, St25tbPollerCmdData* data); + +static St25tbError st25tb_poller_detect_handler(St25tbPoller* poller, St25tbPollerCmdData* data) { + uint8_t uid[ST25TB_UID_SIZE]; + St25tbError error = st25tb_poller_get_uid(poller, uid); + if(error == St25tbErrorNone) { + *data->detect_type.type = st25tb_get_type_from_uid(uid); + } + return error; +} + +static St25tbError + st25tb_poller_read_block_handler(St25tbPoller* poller, St25tbPollerCmdData* data) { + return st25tb_poller_read_block(poller, data->read_block.block, data->read_block.block_num); +} + +static St25tbError + st25tb_poller_write_block_handler(St25tbPoller* poller, St25tbPollerCmdData* data) { + return st25tb_poller_write_block(poller, data->write_block.block, data->write_block.block_num); +} + +static St25tbPollerCmdHandler st25tb_poller_cmd_handlers[St25tbPollerCmdTypeNum] = { + [St25tbPollerCmdTypeDetectType] = st25tb_poller_detect_handler, + [St25tbPollerCmdTypeReadBlock] = st25tb_poller_read_block_handler, + [St25tbPollerCmdTypeWriteBlock] = st25tb_poller_write_block_handler, +}; + +static NfcCommand st25tb_poller_cmd_callback(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.event_data); + furi_assert(event.instance); + furi_assert(event.protocol == NfcProtocolSt25tb); + + St25tbPollerSyncContext* poller_context = context; + St25tbPoller* st25tb_poller = event.instance; + St25tbPollerEvent* st25tb_event = event.event_data; + + if(st25tb_event->type == St25tbPollerEventTypeReady) { + poller_context->error = st25tb_poller_cmd_handlers[poller_context->cmd_type]( + st25tb_poller, &poller_context->cmd_data); + } else { + poller_context->error = st25tb_event->data->error; + } + + furi_thread_flags_set(poller_context->thread_id, ST25TB_POLLER_FLAG_COMMAND_COMPLETE); + + return NfcCommandStop; +} + +static St25tbError st25tb_poller_cmd_execute(Nfc* nfc, St25tbPollerSyncContext* poller_ctx) { + furi_assert(nfc); + furi_assert(poller_ctx->cmd_type < St25tbPollerCmdTypeNum); + poller_ctx->thread_id = furi_thread_get_current_id(); + + NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolSt25tb); + nfc_poller_start(poller, st25tb_poller_cmd_callback, poller_ctx); + furi_thread_flags_wait(ST25TB_POLLER_FLAG_COMMAND_COMPLETE, FuriFlagWaitAny, FuriWaitForever); + furi_thread_flags_clear(ST25TB_POLLER_FLAG_COMMAND_COMPLETE); + + nfc_poller_stop(poller); + nfc_poller_free(poller); + + return poller_ctx->error; +} + +St25tbError st25tb_poller_sync_read_block(Nfc* nfc, uint8_t block_num, uint32_t* block) { + furi_assert(block); + St25tbPollerSyncContext poller_context = { + .cmd_type = St25tbPollerCmdTypeReadBlock, + .cmd_data = + { + .read_block = + { + .block = block, + .block_num = block_num, + }, + }, + }; + return st25tb_poller_cmd_execute(nfc, &poller_context); +} + +St25tbError st25tb_poller_sync_write_block(Nfc* nfc, uint8_t block_num, uint32_t block) { + St25tbPollerSyncContext poller_context = { + .cmd_type = St25tbPollerCmdTypeWriteBlock, + .cmd_data = + { + .write_block = + { + .block = block, + .block_num = block_num, + }, + }, + }; + return st25tb_poller_cmd_execute(nfc, &poller_context); +} + +St25tbError st25tb_poller_sync_detect_type(Nfc* nfc, St25tbType* type) { + furi_assert(type); + St25tbPollerSyncContext poller_context = { + .cmd_type = St25tbPollerCmdTypeDetectType, + .cmd_data = + { + .detect_type = + { + .type = type, + }, + }, + }; + return st25tb_poller_cmd_execute(nfc, &poller_context); +} + +static NfcCommand nfc_scene_read_poller_callback_st25tb(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.event_data); + furi_assert(event.instance); + furi_assert(event.protocol == NfcProtocolSt25tb); + + St25tbPollerSyncContext* poller_context = context; + St25tbPollerEvent* st25tb_event = event.event_data; + + NfcCommand command = NfcCommandContinue; + if(st25tb_event->type == St25tbPollerEventTypeRequestMode) { + st25tb_event->data->mode_request.mode = St25tbPollerModeRead; + } else if( + st25tb_event->type == St25tbPollerEventTypeSuccess || + st25tb_event->type == St25tbPollerEventTypeFailure) { + if(st25tb_event->type == St25tbPollerEventTypeSuccess) { + memcpy( + poller_context->cmd_data.read.data, + st25tb_poller_get_data(event.instance), + sizeof(St25tbData)); + } else { + poller_context->error = st25tb_event->data->error; + } + command = NfcCommandStop; + furi_thread_flags_set(poller_context->thread_id, ST25TB_POLLER_FLAG_COMMAND_COMPLETE); + } + + return command; +} + +St25tbError st25tb_poller_sync_read(Nfc* nfc, St25tbData* data) { + furi_assert(nfc); + furi_assert(data); + + St25tbPollerSyncContext poller_context = { + .thread_id = furi_thread_get_current_id(), + .cmd_data = + { + .read = + { + .data = data, + }, + }, + }; + + NfcPoller* poller = nfc_poller_alloc(nfc, NfcProtocolSt25tb); + nfc_poller_start(poller, nfc_scene_read_poller_callback_st25tb, &poller_context); + furi_thread_flags_wait(ST25TB_POLLER_FLAG_COMMAND_COMPLETE, FuriFlagWaitAny, FuriWaitForever); + furi_thread_flags_clear(ST25TB_POLLER_FLAG_COMMAND_COMPLETE); + + nfc_poller_stop(poller); + nfc_poller_free(poller); + + return poller_context.error; +} \ No newline at end of file diff --git a/lib/nfc/protocols/st25tb/st25tb_poller_sync.h b/lib/nfc/protocols/st25tb/st25tb_poller_sync.h new file mode 100644 index 00000000000..ecd994b3981 --- /dev/null +++ b/lib/nfc/protocols/st25tb/st25tb_poller_sync.h @@ -0,0 +1,20 @@ +#pragma once + +#include "st25tb.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +St25tbError st25tb_poller_sync_read_block(Nfc* nfc, uint8_t block_num, uint32_t* block); + +St25tbError st25tb_poller_sync_write_block(Nfc* nfc, uint8_t block_num, uint32_t block); + +St25tbError st25tb_poller_sync_detect_type(Nfc* nfc, St25tbType* type); + +St25tbError st25tb_poller_sync_read(Nfc* nfc, St25tbData* data); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index cd89b554af8..e735e2c6ddd 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,48.0,, +Version,+,49.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 45c98ae1a5f..e25254dddd2 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,48.0,, +Version,+,49.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -145,6 +145,7 @@ Header,+,lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_sync.h,, Header,+,lib/nfc/protocols/slix/slix.h,, Header,+,lib/nfc/protocols/st25tb/st25tb.h,, Header,+,lib/nfc/protocols/st25tb/st25tb_poller.h,, +Header,+,lib/nfc/protocols/st25tb/st25tb_poller_sync.h,, Header,+,lib/one_wire/maxim_crc.h,, Header,+,lib/one_wire/one_wire_host.h,, Header,+,lib/one_wire/one_wire_slave.h,, @@ -2810,15 +2811,21 @@ Function,+,st25tb_free,void,St25tbData* Function,+,st25tb_get_base_data,St25tbData*,const St25tbData* Function,+,st25tb_get_block_count,uint8_t,St25tbType Function,+,st25tb_get_device_name,const char*,"const St25tbData*, NfcDeviceNameType" +Function,+,st25tb_get_type_from_uid,St25tbType,const uint8_t* Function,+,st25tb_get_uid,const uint8_t*,"const St25tbData*, size_t*" Function,+,st25tb_is_equal,_Bool,"const St25tbData*, const St25tbData*" Function,+,st25tb_load,_Bool,"St25tbData*, FlipperFormat*, uint32_t" -Function,+,st25tb_poller_activate,St25tbError,"St25tbPoller*, St25tbData*" Function,+,st25tb_poller_get_uid,St25tbError,"St25tbPoller*, uint8_t*" Function,+,st25tb_poller_halt,St25tbError,St25tbPoller* Function,+,st25tb_poller_initiate,St25tbError,"St25tbPoller*, uint8_t*" Function,+,st25tb_poller_read_block,St25tbError,"St25tbPoller*, uint32_t*, uint8_t" +Function,+,st25tb_poller_select,St25tbError,"St25tbPoller*, uint8_t*" Function,+,st25tb_poller_send_frame,St25tbError,"St25tbPoller*, const BitBuffer*, BitBuffer*, uint32_t" +Function,+,st25tb_poller_sync_detect_type,St25tbError,"Nfc*, St25tbType*" +Function,+,st25tb_poller_sync_read,St25tbError,"Nfc*, St25tbData*" +Function,+,st25tb_poller_sync_read_block,St25tbError,"Nfc*, uint8_t, uint32_t*" +Function,+,st25tb_poller_sync_write_block,St25tbError,"Nfc*, uint8_t, uint32_t" +Function,+,st25tb_poller_write_block,St25tbError,"St25tbPoller*, uint32_t, uint8_t" Function,+,st25tb_reset,void,St25tbData* Function,+,st25tb_save,_Bool,"const St25tbData*, FlipperFormat*" Function,+,st25tb_set_uid,_Bool,"St25tbData*, const uint8_t*, size_t" From b51a754fd95285069c360afa48de380e6311c8e2 Mon Sep 17 00:00:00 2001 From: Augusto Zanellato Date: Fri, 1 Dec 2023 14:25:53 +0100 Subject: [PATCH 07/14] Mifare Classic nested auth support (#3238) Co-authored-by: Aleksandr Kutuzov --- lib/nfc/protocols/mf_classic/crypto1.c | 9 +- lib/nfc/protocols/mf_classic/crypto1.h | 3 +- .../protocols/mf_classic/mf_classic_poller.h | 40 +++++++++ .../mf_classic/mf_classic_poller_i.c | 89 ++++++++++++++++--- targets/f18/api_symbols.csv | 2 +- targets/f7/api_symbols.csv | 4 +- 6 files changed, 128 insertions(+), 19 deletions(-) diff --git a/lib/nfc/protocols/mf_classic/crypto1.c b/lib/nfc/protocols/mf_classic/crypto1.c index df01a348c85..02bc677ba69 100644 --- a/lib/nfc/protocols/mf_classic/crypto1.c +++ b/lib/nfc/protocols/mf_classic/crypto1.c @@ -143,7 +143,8 @@ void crypto1_encrypt_reader_nonce( uint32_t cuid, uint8_t* nt, uint8_t* nr, - BitBuffer* out) { + BitBuffer* out, + bool is_nested) { furi_assert(crypto); furi_assert(nt); furi_assert(nr); @@ -153,7 +154,11 @@ void crypto1_encrypt_reader_nonce( uint32_t nt_num = nfc_util_bytes2num(nt, sizeof(uint32_t)); crypto1_init(crypto, key); - crypto1_word(crypto, nt_num ^ cuid, 0); + if(is_nested) { + nt_num = crypto1_word(crypto, nt_num ^ cuid, 1) ^ nt_num; + } else { + crypto1_word(crypto, nt_num ^ cuid, 0); + } for(size_t i = 0; i < 4; i++) { uint8_t byte = crypto1_byte(crypto, nr[i], 0) ^ nr[i]; diff --git a/lib/nfc/protocols/mf_classic/crypto1.h b/lib/nfc/protocols/mf_classic/crypto1.h index f2bdb272b0e..7cc16fcffde 100644 --- a/lib/nfc/protocols/mf_classic/crypto1.h +++ b/lib/nfc/protocols/mf_classic/crypto1.h @@ -35,7 +35,8 @@ void crypto1_encrypt_reader_nonce( uint32_t cuid, uint8_t* nt, uint8_t* nr, - BitBuffer* out); + BitBuffer* out, + bool is_nested); uint32_t prng_successor(uint32_t x, uint32_t n); diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller.h b/lib/nfc/protocols/mf_classic/mf_classic_poller.h index f05a6800ad1..19e52570175 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller.h +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller.h @@ -178,6 +178,25 @@ MfClassicError mf_classic_poller_get_nt( MfClassicKeyType key_type, MfClassicNt* nt); +/** + * @brief Collect tag nonce during nested authentication. + * + * Must ONLY be used inside the callback function. + * + * Starts nested authentication procedure and collects tag nonce. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] block_num block number for authentication. + * @param[in] key_type key type to be used for authentication. + * @param[out] nt pointer to the MfClassicNt structure to be filled with nonce data. + * @return MfClassicErrorNone on success, an error code on failure. + */ +MfClassicError mf_classic_poller_get_nt_nested( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKeyType key_type, + MfClassicNt* nt); + /** * @brief Perform authentication. * @@ -200,6 +219,27 @@ MfClassicError mf_classic_poller_auth( MfClassicKeyType key_type, MfClassicAuthContext* data); +/** + * @brief Perform nested authentication. + * + * Must ONLY be used inside the callback function. + * + * Perform nested authentication as specified in Mf Classic protocol. + * + * @param[in, out] instance pointer to the instance to be used in the transaction. + * @param[in] block_num block number for authentication. + * @param[in] key key to be used for authentication. + * @param[in] key_type key type to be used for authentication. + * @param[out] data pointer to MfClassicAuthContext structure to be filled with authentication data. + * @return MfClassicErrorNone on success, an error code on failure. + */ +MfClassicError mf_classic_poller_auth_nested( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + MfClassicAuthContext* data); + /** * @brief Halt the tag. * diff --git a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c index 4b071815ea8..16bfb3f7282 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_poller_i.c @@ -33,11 +33,12 @@ MfClassicError mf_classic_process_error(Iso14443_3aError error) { return ret; } -MfClassicError mf_classic_poller_get_nt( +static MfClassicError mf_classic_poller_get_nt_common( MfClassicPoller* instance, uint8_t block_num, MfClassicKeyType key_type, - MfClassicNt* nt) { + MfClassicNt* nt, + bool is_nested) { MfClassicError ret = MfClassicErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; @@ -47,14 +48,29 @@ MfClassicError mf_classic_poller_get_nt( uint8_t auth_cmd[2] = {auth_type, block_num}; bit_buffer_copy_bytes(instance->tx_plain_buffer, auth_cmd, sizeof(auth_cmd)); - error = iso14443_3a_poller_send_standard_frame( - instance->iso14443_3a_poller, - instance->tx_plain_buffer, - instance->rx_plain_buffer, - MF_CLASSIC_FWT_FC); - if(error != Iso14443_3aErrorWrongCrc) { - ret = mf_classic_process_error(error); - break; + if(is_nested) { + iso14443_crc_append(Iso14443CrcTypeA, instance->tx_plain_buffer); + crypto1_encrypt( + instance->crypto, NULL, instance->tx_plain_buffer, instance->tx_encrypted_buffer); + error = iso14443_3a_poller_txrx_custom_parity( + instance->iso14443_3a_poller, + instance->tx_encrypted_buffer, + instance->rx_plain_buffer, // NT gets decrypted by mf_classic_async_auth + MF_CLASSIC_FWT_FC); + if(error != Iso14443_3aErrorNone) { + ret = mf_classic_process_error(error); + break; + } + } else { + error = iso14443_3a_poller_send_standard_frame( + instance->iso14443_3a_poller, + instance->tx_plain_buffer, + instance->rx_plain_buffer, + MF_CLASSIC_FWT_FC); + if(error != Iso14443_3aErrorWrongCrc) { + ret = mf_classic_process_error(error); + break; + } } if(bit_buffer_get_size_bytes(instance->rx_plain_buffer) != sizeof(MfClassicNt)) { ret = MfClassicErrorProtocol; @@ -69,12 +85,29 @@ MfClassicError mf_classic_poller_get_nt( return ret; } -MfClassicError mf_classic_poller_auth( +MfClassicError mf_classic_poller_get_nt( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKeyType key_type, + MfClassicNt* nt) { + return mf_classic_poller_get_nt_common(instance, block_num, key_type, nt, false); +} + +MfClassicError mf_classic_poller_get_nt_nested( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKeyType key_type, + MfClassicNt* nt) { + return mf_classic_poller_get_nt_common(instance, block_num, key_type, nt, true); +} + +static MfClassicError mf_classic_poller_auth_common( MfClassicPoller* instance, uint8_t block_num, MfClassicKey* key, MfClassicKeyType key_type, - MfClassicAuthContext* data) { + MfClassicAuthContext* data, + bool is_nested) { MfClassicError ret = MfClassicErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; @@ -84,7 +117,11 @@ MfClassicError mf_classic_poller_auth( iso14443_3a_poller_get_data(instance->iso14443_3a_poller)); MfClassicNt nt = {}; - ret = mf_classic_poller_get_nt(instance, block_num, key_type, &nt); + if(is_nested) { + ret = mf_classic_poller_get_nt_nested(instance, block_num, key_type, &nt); + } else { + ret = mf_classic_poller_get_nt(instance, block_num, key_type, &nt); + } if(ret != MfClassicErrorNone) break; if(data) { data->nt = nt; @@ -96,7 +133,13 @@ MfClassicError mf_classic_poller_auth( furi_hal_random_fill_buf(nr.data, sizeof(MfClassicNr)); crypto1_encrypt_reader_nonce( - instance->crypto, key_num, cuid, nt.data, nr.data, instance->tx_encrypted_buffer); + instance->crypto, + key_num, + cuid, + nt.data, + nr.data, + instance->tx_encrypted_buffer, + is_nested); error = iso14443_3a_poller_txrx_custom_parity( instance->iso14443_3a_poller, instance->tx_encrypted_buffer, @@ -130,6 +173,24 @@ MfClassicError mf_classic_poller_auth( return ret; } +MfClassicError mf_classic_poller_auth( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + MfClassicAuthContext* data) { + return mf_classic_poller_auth_common(instance, block_num, key, key_type, data, false); +} + +MfClassicError mf_classic_poller_auth_nested( + MfClassicPoller* instance, + uint8_t block_num, + MfClassicKey* key, + MfClassicKeyType key_type, + MfClassicAuthContext* data) { + return mf_classic_poller_auth_common(instance, block_num, key, key_type, data, true); +} + MfClassicError mf_classic_poller_halt(MfClassicPoller* instance) { MfClassicError ret = MfClassicErrorNone; Iso14443_3aError error = Iso14443_3aErrorNone; diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index e735e2c6ddd..cb34f969adc 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,49.0,, +Version,+,49.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index e25254dddd2..439fc7bf5a5 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,49.0,, +Version,+,49.1,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -2288,6 +2288,8 @@ Function,+,mf_classic_is_sector_trailer,_Bool,uint8_t Function,+,mf_classic_is_value_block,_Bool,"MfClassicSectorTrailer*, uint8_t" Function,+,mf_classic_load,_Bool,"MfClassicData*, FlipperFormat*, uint32_t" Function,+,mf_classic_poller_auth,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" +Function,+,mf_classic_poller_auth_nested,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKey*, MfClassicKeyType, MfClassicAuthContext*" +Function,+,mf_classic_poller_get_nt_nested,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKeyType, MfClassicNt*" Function,+,mf_classic_poller_get_nt,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicKeyType, MfClassicNt*" Function,+,mf_classic_poller_halt,MfClassicError,MfClassicPoller* Function,+,mf_classic_poller_read_block,MfClassicError,"MfClassicPoller*, uint8_t, MfClassicBlock*" From 6a5d63803aeadc9f2b3cb4f150bb32dee841dc03 Mon Sep 17 00:00:00 2001 From: RebornedBrain <138568282+RebornedBrain@users.noreply.github.com> Date: Sat, 2 Dec 2023 07:45:47 +0300 Subject: [PATCH 08/14] [FL-3675] Ntag21x write (#3246) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * New scenes for ultralight poller write mode * Added new button and transition logic for write operation For now write is only possible for NTAG21x cards with default password and no AUTHLIM set * Poller states extended * Enums and datatypes extended for new poller mode * Added mode field to poller instance datatype * New states for poller added in order to implement write mode * Added new event type for locked cards in order to simplify state flow * New logic for poller write commands * Scenes adjustments * Scenes renamed * New field added to poller instance * Now we write in 'page per call' mode * Now function takes callback return value into account * Callback will be called only in write mode * Event type added * Log adjusted and start page to write set * Logs added and check in now false at start, then it moves to true * Now mf_ultralight_poller_handler_request_write_data halts card in case of check failure and stops poller * All fail events now returns NfcCommandStop callback * In case of fail we move back properly * Remove garbage Co-authored-by: gornekich Co-authored-by: あく --- .../mf_ultralight/mf_ultralight.c | 13 ++ .../main/nfc/scenes/nfc_scene_config.h | 4 + .../scenes/nfc_scene_mf_ultralight_write.c | 119 +++++++++++++++ .../nfc_scene_mf_ultralight_write_fail.c | 67 +++++++++ .../nfc_scene_mf_ultralight_write_success.c | 43 ++++++ .../nfc_scene_mf_ultralight_wrong_card.c | 58 ++++++++ .../mf_ultralight/mf_ultralight_poller.c | 139 +++++++++++++++++- .../mf_ultralight/mf_ultralight_poller.h | 16 ++ .../mf_ultralight/mf_ultralight_poller_i.h | 7 + 9 files changed, 462 insertions(+), 4 deletions(-) create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_write.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_fail.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_success.c create mode 100644 applications/main/nfc/scenes/nfc_scene_mf_ultralight_wrong_card.c diff --git a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c index c4fd04c7e5a..3e27fc539e6 100644 --- a/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c +++ b/applications/main/nfc/helpers/protocol_support/mf_ultralight/mf_ultralight.c @@ -12,6 +12,7 @@ enum { SubmenuIndexUnlock = SubmenuIndexCommonMax, SubmenuIndexUnlockByReader, SubmenuIndexUnlockByPassword, + SubmenuIndexWrite, }; static void nfc_scene_info_on_enter_mf_ultralight(NfcApp* instance) { @@ -106,6 +107,15 @@ static void nfc_scene_read_and_saved_menu_on_enter_mf_ultralight(NfcApp* instanc SubmenuIndexUnlock, nfc_protocol_support_common_submenu_callback, instance); + } else if( + data->type == MfUltralightTypeNTAG213 || data->type == MfUltralightTypeNTAG215 || + data->type == MfUltralightTypeNTAG216) { + submenu_add_item( + submenu, + "Write", + SubmenuIndexWrite, + nfc_protocol_support_common_submenu_callback, + instance); } } @@ -146,6 +156,9 @@ static bool if(event == SubmenuIndexUnlock) { scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightUnlockMenu); return true; + } else if(event == SubmenuIndexWrite) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWrite); + return true; } return false; } diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index f415c66a6fa..a9887996d6d 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -24,6 +24,10 @@ ADD_SCENE(nfc, field, Field) ADD_SCENE(nfc, retry_confirm, RetryConfirm) ADD_SCENE(nfc, exit_confirm, ExitConfirm) +ADD_SCENE(nfc, mf_ultralight_write, MfUltralightWrite) +ADD_SCENE(nfc, mf_ultralight_write_success, MfUltralightWriteSuccess) +ADD_SCENE(nfc, mf_ultralight_write_fail, MfUltralightWriteFail) +ADD_SCENE(nfc, mf_ultralight_wrong_card, MfUltralightWrongCard) ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu) ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn) ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write.c new file mode 100644 index 00000000000..b3c1beef5ab --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write.c @@ -0,0 +1,119 @@ +#include "../nfc_app_i.h" + +#include + +enum { + NfcSceneMfUltralightWriteStateCardSearch, + NfcSceneMfUltralightWriteStateCardFound, +}; + +NfcCommand nfc_scene_mf_ultralight_write_worker_callback(NfcGenericEvent event, void* context) { + furi_assert(context); + furi_assert(event.event_data); + furi_assert(event.protocol == NfcProtocolMfUltralight); + + NfcCommand command = NfcCommandContinue; + NfcApp* instance = context; + MfUltralightPollerEvent* mfu_event = event.event_data; + + if(mfu_event->type == MfUltralightPollerEventTypeRequestMode) { + mfu_event->data->poller_mode = MfUltralightPollerModeWrite; + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventCardDetected); + } else if(mfu_event->type == MfUltralightPollerEventTypeAuthRequest) { + mfu_event->data->auth_context.skip_auth = true; + } else if(mfu_event->type == MfUltralightPollerEventTypeRequestWriteData) { + mfu_event->data->write_data = + nfc_device_get_data(instance->nfc_device, NfcProtocolMfUltralight); + } else if(mfu_event->type == MfUltralightPollerEventTypeCardMismatch) { + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventWrongCard); + command = NfcCommandStop; + } else if(mfu_event->type == MfUltralightPollerEventTypeCardLocked) { + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerFailure); + command = NfcCommandStop; + } else if(mfu_event->type == MfUltralightPollerEventTypeWriteFail) { + command = NfcCommandStop; + } else if(mfu_event->type == MfUltralightPollerEventTypeWriteSuccess) { + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess); + command = NfcCommandStop; + } + return command; +} + +static void nfc_scene_mf_ultralight_write_setup_view(NfcApp* instance) { + Popup* popup = instance->popup; + popup_reset(popup); + uint32_t state = + scene_manager_get_scene_state(instance->scene_manager, NfcSceneMfUltralightWrite); + + if(state == NfcSceneMfUltralightWriteStateCardSearch) { + popup_set_text( + instance->popup, "Apply the initial\ncard only", 128, 32, AlignRight, AlignCenter); + popup_set_icon(instance->popup, 0, 8, &I_NFC_manual_60x50); + } else { + popup_set_header(popup, "Writing\nDon't move...", 52, 32, AlignLeft, AlignCenter); + popup_set_icon(popup, 12, 23, &A_Loading_24); + } + + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); +} + +void nfc_scene_mf_ultralight_write_on_enter(void* context) { + NfcApp* instance = context; + dolphin_deed(DolphinDeedNfcEmulate); + + scene_manager_set_scene_state( + instance->scene_manager, + NfcSceneMfUltralightWrite, + NfcSceneMfUltralightWriteStateCardSearch); + nfc_scene_mf_ultralight_write_setup_view(instance); + + // Setup and start worker + FURI_LOG_D("WMFU", "Card searching..."); + instance->poller = nfc_poller_alloc(instance->nfc, NfcProtocolMfUltralight); + nfc_poller_start(instance->poller, nfc_scene_mf_ultralight_write_worker_callback, instance); + + nfc_blink_emulate_start(instance); +} + +bool nfc_scene_mf_ultralight_write_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventCardDetected) { + scene_manager_set_scene_state( + instance->scene_manager, + NfcSceneMfUltralightWrite, + NfcSceneMfUltralightWriteStateCardFound); + nfc_scene_mf_ultralight_write_setup_view(instance); + consumed = true; + } else if(event.event == NfcCustomEventWrongCard) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWrongCard); + consumed = true; + } else if(event.event == NfcCustomEventPollerSuccess) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWriteSuccess); + consumed = true; + } else if(event.event == NfcCustomEventPollerFailure) { + scene_manager_next_scene(instance->scene_manager, NfcSceneMfUltralightWriteFail); + consumed = true; + } + } + + return consumed; +} + +void nfc_scene_mf_ultralight_write_on_exit(void* context) { + NfcApp* instance = context; + + nfc_poller_stop(instance->poller); + nfc_poller_free(instance->poller); + + scene_manager_set_scene_state( + instance->scene_manager, + NfcSceneMfUltralightWrite, + NfcSceneMfUltralightWriteStateCardSearch); + // Clear view + popup_reset(instance->popup); + + nfc_blink_stop(instance); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_fail.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_fail.c new file mode 100644 index 00000000000..dff5f278153 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_fail.c @@ -0,0 +1,67 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_ultralight_write_fail_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcApp* instance = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(instance->view_dispatcher, result); + } +} + +void nfc_scene_mf_ultralight_write_fail_on_enter(void* context) { + NfcApp* instance = context; + Widget* widget = instance->widget; + + notification_message(instance->notifications, &sequence_error); + + widget_add_icon_element(widget, 72, 17, &I_DolphinCommon_56x48); + widget_add_string_element( + widget, 7, 4, AlignLeft, AlignTop, FontPrimary, "Writing gone wrong!"); + widget_add_string_multiline_element( + widget, + 7, + 17, + AlignLeft, + AlignTop, + FontSecondary, + "Card protected by\npassword, AUTH0\nor lock bits"); + + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Finish", + nfc_scene_mf_ultralight_write_fail_widget_callback, + instance); + + // Setup and start worker + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget); +} + +static bool nfc_scene_mf_ultralight_write_fail_move_to_back_scene(const NfcApp* const instance) { + bool was_saved = scene_manager_has_previous_scene(instance->scene_manager, NfcSceneSavedMenu); + uint32_t scene_id = was_saved ? NfcSceneSavedMenu : NfcSceneReadMenu; + + return scene_manager_search_and_switch_to_previous_scene(instance->scene_manager, scene_id); +} + +bool nfc_scene_mf_ultralight_write_fail_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = nfc_scene_mf_ultralight_write_fail_move_to_back_scene(instance); + } + } else if(event.type == SceneManagerEventTypeBack) { + consumed = nfc_scene_mf_ultralight_write_fail_move_to_back_scene(instance); + } + return consumed; +} + +void nfc_scene_mf_ultralight_write_fail_on_exit(void* context) { + NfcApp* instance = context; + + widget_reset(instance->widget); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_success.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_success.c new file mode 100644 index 00000000000..c1fbc35ee54 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_write_success.c @@ -0,0 +1,43 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_ultralight_write_success_popup_callback(void* context) { + NfcApp* instance = context; + view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventViewExit); +} + +void nfc_scene_mf_ultralight_write_success_on_enter(void* context) { + NfcApp* instance = context; + dolphin_deed(DolphinDeedNfcSave); + + notification_message(instance->notifications, &sequence_success); + + Popup* popup = instance->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Successfully\nwritten", 13, 22, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, instance); + popup_set_callback(popup, nfc_scene_mf_ultralight_write_success_popup_callback); + popup_enable_timeout(popup); + + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewPopup); +} + +bool nfc_scene_mf_ultralight_write_success_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == NfcCustomEventViewExit) { + consumed = scene_manager_search_and_switch_to_previous_scene( + instance->scene_manager, NfcSceneSavedMenu); + } + } + return consumed; +} + +void nfc_scene_mf_ultralight_write_success_on_exit(void* context) { + NfcApp* instance = context; + + // Clear view + popup_reset(instance->popup); +} diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_wrong_card.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_wrong_card.c new file mode 100644 index 00000000000..a225c474db8 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_wrong_card.c @@ -0,0 +1,58 @@ +#include "../nfc_app_i.h" + +void nfc_scene_mf_ultralight_wrong_card_widget_callback( + GuiButtonType result, + InputType type, + void* context) { + NfcApp* instance = context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(instance->view_dispatcher, result); + } +} + +void nfc_scene_mf_ultralight_wrong_card_on_enter(void* context) { + NfcApp* instance = context; + Widget* widget = instance->widget; + + notification_message(instance->notifications, &sequence_error); + + widget_add_icon_element(widget, 73, 17, &I_DolphinCommon_56x48); + widget_add_string_element( + widget, 3, 4, AlignLeft, AlignTop, FontPrimary, "This is wrong card"); + widget_add_string_multiline_element( + widget, + 4, + 17, + AlignLeft, + AlignTop, + FontSecondary, + "Card of the same\ntype should be\n presented"); + //"Data management\nis only possible\nwith card of same type"); + widget_add_button_element( + widget, + GuiButtonTypeLeft, + "Retry", + nfc_scene_mf_ultralight_wrong_card_widget_callback, + instance); + + // Setup and start worker + view_dispatcher_switch_to_view(instance->view_dispatcher, NfcViewWidget); +} + +bool nfc_scene_mf_ultralight_wrong_card_on_event(void* context, SceneManagerEvent event) { + NfcApp* instance = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeLeft) { + consumed = scene_manager_previous_scene(instance->scene_manager); + } + } + return consumed; +} + +void nfc_scene_mf_ultralight_wrong_card_on_exit(void* context) { + NfcApp* instance = context; + + widget_reset(instance->widget); +} \ No newline at end of file diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c index 86ab68c8b14..619cd8c5fbc 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.c @@ -224,11 +224,24 @@ static NfcCommand mf_ultralight_poller_handler_idle(MfUltralightPoller* instance instance->tearing_flag_read = 0; instance->tearing_flag_total = 3; instance->pages_read = 0; - instance->state = MfUltralightPollerStateReadVersion; - + instance->state = MfUltralightPollerStateRequestMode; + instance->current_page = 0; return NfcCommandContinue; } +static NfcCommand mf_ultralight_poller_handler_request_mode(MfUltralightPoller* instance) { + NfcCommand command = NfcCommandContinue; + + instance->mfu_event.type = MfUltralightPollerEventTypeRequestMode; + instance->mfu_event.data->poller_mode = MfUltralightPollerModeRead; + + command = instance->callback(instance->general_event, instance->context); + instance->mode = instance->mfu_event.data->poller_mode; + + instance->state = MfUltralightPollerStateReadVersion; + return command; +} + static NfcCommand mf_ultralight_poller_handler_read_version(MfUltralightPoller* instance) { instance->error = mf_ultralight_poller_read_version(instance, &instance->data->version); if(instance->error == MfUltralightErrorNone) { @@ -259,6 +272,7 @@ static NfcCommand mf_ultralight_poller_handler_check_ultralight_c(MfUltralightPo } static NfcCommand mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller* instance) { + MfUltralightPollerState next_state = MfUltralightPollerStateGetFeatureSet; MfUltralightPageReadCommandData data = {}; instance->error = mf_ultralight_poller_read_page(instance, 41, &data); if(instance->error == MfUltralightErrorNone) { @@ -268,8 +282,13 @@ static NfcCommand mf_ultralight_poller_handler_check_ntag_203(MfUltralightPoller FURI_LOG_D(TAG, "Original Ultralight detected"); iso14443_3a_poller_halt(instance->iso14443_3a_poller); instance->data->type = MfUltralightTypeUnknown; + if(instance->mode == MfUltralightPollerModeWrite) { + instance->mfu_event.type = MfUltralightPollerEventTypeCardMismatch; + instance->callback(instance->general_event, instance->context); + next_state = MfUltralightPollerStateWriteFail; + } } - instance->state = MfUltralightPollerStateGetFeatureSet; + instance->state = next_state; return NfcCommandContinue; } @@ -508,6 +527,7 @@ static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoll static NfcCommand mf_ultralight_poller_handler_read_fail(MfUltralightPoller* instance) { FURI_LOG_D(TAG, "Read Failed"); iso14443_3a_poller_halt(instance->iso14443_3a_poller); + instance->mfu_event.type = MfUltralightPollerEventTypeReadFailed; instance->mfu_event.data->error = instance->error; NfcCommand command = instance->callback(instance->general_event, instance->context); instance->state = MfUltralightPollerStateIdle; @@ -516,15 +536,121 @@ static NfcCommand mf_ultralight_poller_handler_read_fail(MfUltralightPoller* ins static NfcCommand mf_ultralight_poller_handler_read_success(MfUltralightPoller* instance) { FURI_LOG_D(TAG, "Read success"); - iso14443_3a_poller_halt(instance->iso14443_3a_poller); instance->mfu_event.type = MfUltralightPollerEventTypeReadSuccess; NfcCommand command = instance->callback(instance->general_event, instance->context); + + if(instance->mode == MfUltralightPollerModeRead) { + iso14443_3a_poller_halt(instance->iso14443_3a_poller); + instance->state = MfUltralightPollerStateIdle; + } else { + instance->state = MfUltralightPollerStateRequestWriteData; + } + + return command; +} + +static NfcCommand mf_ultralight_poller_handler_request_write_data(MfUltralightPoller* instance) { + FURI_LOG_D(TAG, "Check writing capability"); + NfcCommand command = NfcCommandContinue; + MfUltralightPollerState next_state = MfUltralightPollerStateWritePages; + instance->current_page = 4; + + instance->mfu_event.type = MfUltralightPollerEventTypeRequestWriteData; + instance->callback(instance->general_event, instance->context); + + const MfUltralightData* write_data = instance->mfu_event.data->write_data; + const MfUltralightData* tag_data = instance->data; + uint32_t features = mf_ultralight_get_feature_support_set(tag_data->type); + + bool check_passed = false; + do { + if(write_data->type != tag_data->type) { + FURI_LOG_D(TAG, "Incorrect tag type"); + instance->mfu_event.type = MfUltralightPollerEventTypeCardMismatch; + break; + } + + if(!instance->auth_context.auth_success) { + FURI_LOG_D(TAG, "Unknown password"); + instance->mfu_event.type = MfUltralightPollerEventTypeCardLocked; + break; + } + + const MfUltralightPage staticlock_page = tag_data->page[2]; + if(staticlock_page.data[2] != 0 || staticlock_page.data[3] != 0) { + FURI_LOG_D(TAG, "Static lock bits are set"); + instance->mfu_event.type = MfUltralightPollerEventTypeCardLocked; + break; + } + + if(mf_ultralight_support_feature(features, MfUltralightFeatureSupportDynamicLock)) { + uint8_t dynlock_num = mf_ultralight_get_config_page_num(tag_data->type) - 1; + const MfUltralightPage dynlock_page = tag_data->page[dynlock_num]; + if(dynlock_page.data[0] != 0 || dynlock_page.data[1] != 0) { + FURI_LOG_D(TAG, "Dynamic lock bits are set"); + instance->mfu_event.type = MfUltralightPollerEventTypeCardLocked; + break; + } + } + + check_passed = true; + } while(false); + + if(!check_passed) { + iso14443_3a_poller_halt(instance->iso14443_3a_poller); + command = instance->callback(instance->general_event, instance->context); + next_state = MfUltralightPollerStateWriteFail; + } + + instance->state = next_state; + return command; +} + +static NfcCommand mf_ultralight_poller_handler_write_pages(MfUltralightPoller* instance) { + NfcCommand command = NfcCommandContinue; + + do { + const MfUltralightData* write_data = instance->mfu_event.data->write_data; + uint8_t end_page = mf_ultralight_get_config_page_num(write_data->type) - 1; + if(instance->current_page == end_page) { + instance->state = MfUltralightPollerStateWriteSuccess; + break; + } + FURI_LOG_D(TAG, "Writing page %d", instance->current_page); + MfUltralightError error = mf_ultralight_poller_write_page( + instance, instance->current_page, &write_data->page[instance->current_page]); + if(error != MfUltralightErrorNone) { + instance->state = MfUltralightPollerStateWriteFail; + instance->error = error; + break; + } + instance->current_page++; + } while(false); + + return command; +} + +static NfcCommand mf_ultralight_poller_handler_write_fail(MfUltralightPoller* instance) { + FURI_LOG_D(TAG, "Write failed"); + iso14443_3a_poller_halt(instance->iso14443_3a_poller); + instance->mfu_event.data->error = instance->error; + instance->mfu_event.type = MfUltralightPollerEventTypeWriteFail; + NfcCommand command = instance->callback(instance->general_event, instance->context); + return command; +} + +static NfcCommand mf_ultralight_poller_handler_write_success(MfUltralightPoller* instance) { + FURI_LOG_D(TAG, "Write success"); + iso14443_3a_poller_halt(instance->iso14443_3a_poller); + instance->mfu_event.type = MfUltralightPollerEventTypeWriteSuccess; + NfcCommand command = instance->callback(instance->general_event, instance->context); return command; } static const MfUltralightPollerReadHandler mf_ultralight_poller_read_handler[MfUltralightPollerStateNum] = { [MfUltralightPollerStateIdle] = mf_ultralight_poller_handler_idle, + [MfUltralightPollerStateRequestMode] = mf_ultralight_poller_handler_request_mode, [MfUltralightPollerStateReadVersion] = mf_ultralight_poller_handler_read_version, [MfUltralightPollerStateDetectMfulC] = mf_ultralight_poller_handler_check_ultralight_c, [MfUltralightPollerStateDetectNtag203] = mf_ultralight_poller_handler_check_ntag_203, @@ -538,6 +664,11 @@ static const MfUltralightPollerReadHandler [MfUltralightPollerStateReadPages] = mf_ultralight_poller_handler_read_pages, [MfUltralightPollerStateReadFailed] = mf_ultralight_poller_handler_read_fail, [MfUltralightPollerStateReadSuccess] = mf_ultralight_poller_handler_read_success, + [MfUltralightPollerStateRequestWriteData] = + mf_ultralight_poller_handler_request_write_data, + [MfUltralightPollerStateWritePages] = mf_ultralight_poller_handler_write_pages, + [MfUltralightPollerStateWriteFail] = mf_ultralight_poller_handler_write_fail, + [MfUltralightPollerStateWriteSuccess] = mf_ultralight_poller_handler_write_success, }; diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h index 665d90cb700..2343be089bf 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller.h @@ -16,13 +16,27 @@ typedef struct MfUltralightPoller MfUltralightPoller; * @brief Enumeration of possible MfUltralight poller event types. */ typedef enum { + MfUltralightPollerEventTypeRequestMode, /**< Poller requests for operating mode. */ MfUltralightPollerEventTypeAuthRequest, /**< Poller requests to fill authentication context. */ MfUltralightPollerEventTypeAuthSuccess, /**< Authentication succeeded. */ MfUltralightPollerEventTypeAuthFailed, /**< Authentication failed. */ MfUltralightPollerEventTypeReadSuccess, /**< Poller read card successfully. */ MfUltralightPollerEventTypeReadFailed, /**< Poller failed to read card. */ + MfUltralightPollerEventTypeRequestWriteData, /**< Poller request card data for write operation. */ + MfUltralightPollerEventTypeCardMismatch, /**< Type of card for writing differs from presented one. */ + MfUltralightPollerEventTypeCardLocked, /**< Presented card is locked by password, AUTH0 or lock bytes. */ + MfUltralightPollerEventTypeWriteSuccess, /**< Poller wrote card successfully. */ + MfUltralightPollerEventTypeWriteFail, /**< Poller failed to write card. */ } MfUltralightPollerEventType; +/** + * @brief Enumeration of possible MfUltralight poller operating modes. + */ +typedef enum { + MfUltralightPollerModeRead, /**< Poller will only read card. It's a default mode. */ + MfUltralightPollerModeWrite, /**< Poller will write already saved card to another presented card. */ +} MfUltralightPollerMode; + /** * @brief MfUltralight poller authentication context. */ @@ -39,6 +53,8 @@ typedef struct { typedef union { MfUltralightPollerAuthContext auth_context; /**< Authentication context. */ MfUltralightError error; /**< Error code indicating reading fail reason. */ + const MfUltralightData* write_data; + MfUltralightPollerMode poller_mode; } MfUltralightPollerEventData; /** diff --git a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h index c89402b421c..7c7354b1c6d 100644 --- a/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h +++ b/lib/nfc/protocols/mf_ultralight/mf_ultralight_poller_i.h @@ -49,6 +49,7 @@ typedef union { typedef enum { MfUltralightPollerStateIdle, + MfUltralightPollerStateRequestMode, MfUltralightPollerStateReadVersion, MfUltralightPollerStateDetectMfulC, MfUltralightPollerStateDetectNtag203, @@ -61,6 +62,10 @@ typedef enum { MfUltralightPollerStateTryDefaultPass, MfUltralightPollerStateReadFailed, MfUltralightPollerStateReadSuccess, + MfUltralightPollerStateRequestWriteData, + MfUltralightPollerStateWritePages, + MfUltralightPollerStateWriteFail, + MfUltralightPollerStateWriteSuccess, MfUltralightPollerStateNum, } MfUltralightPollerState; @@ -68,6 +73,7 @@ typedef enum { struct MfUltralightPoller { Iso14443_3aPoller* iso14443_3a_poller; MfUltralightPollerState state; + MfUltralightPollerMode mode; BitBuffer* tx_buffer; BitBuffer* rx_buffer; MfUltralightData* data; @@ -79,6 +85,7 @@ struct MfUltralightPoller { uint8_t counters_total; uint8_t tearing_flag_read; uint8_t tearing_flag_total; + uint16_t current_page; MfUltralightError error; NfcGenericEvent general_event; From 93732865acac9053cb0c580a2bf3e58962b3a678 Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Sat, 2 Dec 2023 08:52:04 +0400 Subject: [PATCH 09/14] [FL-3132] HID app: Add new function key icons (#3236) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add new function key icons * Fix graphical glitches on the buttons Co-authored-by: あく --- applications/system/hid_app/assets/Alt_11x7.png | Bin 2417 -> 0 bytes applications/system/hid_app/assets/Alt_17x10.png | Bin 0 -> 550 bytes applications/system/hid_app/assets/Cmd_15x7.png | Bin 2426 -> 0 bytes applications/system/hid_app/assets/Cmd_17x10.png | Bin 0 -> 556 bytes applications/system/hid_app/assets/Ctrl_15x7.png | Bin 2433 -> 0 bytes .../system/hid_app/assets/Ctrl_17x10.png | Bin 0 -> 552 bytes applications/system/hid_app/assets/Del_12x7.png | Bin 2417 -> 0 bytes applications/system/hid_app/assets/Del_17x10.png | Bin 0 -> 551 bytes applications/system/hid_app/assets/Esc_14x7.png | Bin 2430 -> 0 bytes applications/system/hid_app/assets/Esc_17x10.png | Bin 0 -> 550 bytes applications/system/hid_app/assets/Tab_15x7.png | Bin 2419 -> 0 bytes applications/system/hid_app/assets/Tab_17x10.png | Bin 0 -> 549 bytes applications/system/hid_app/views/hid_keyboard.c | 14 +++++++------- 13 files changed, 7 insertions(+), 7 deletions(-) delete mode 100644 applications/system/hid_app/assets/Alt_11x7.png create mode 100644 applications/system/hid_app/assets/Alt_17x10.png delete mode 100644 applications/system/hid_app/assets/Cmd_15x7.png create mode 100644 applications/system/hid_app/assets/Cmd_17x10.png delete mode 100644 applications/system/hid_app/assets/Ctrl_15x7.png create mode 100644 applications/system/hid_app/assets/Ctrl_17x10.png delete mode 100644 applications/system/hid_app/assets/Del_12x7.png create mode 100644 applications/system/hid_app/assets/Del_17x10.png delete mode 100644 applications/system/hid_app/assets/Esc_14x7.png create mode 100644 applications/system/hid_app/assets/Esc_17x10.png delete mode 100644 applications/system/hid_app/assets/Tab_15x7.png create mode 100644 applications/system/hid_app/assets/Tab_17x10.png diff --git a/applications/system/hid_app/assets/Alt_11x7.png b/applications/system/hid_app/assets/Alt_11x7.png deleted file mode 100644 index 3e4bf320ee313c725e228356b6bf58989e804441..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2417 zcmbtVdsGu=79SqVBOtIXmWphdCPf~SC-O=|SV#a}0MIvsdA#66UH}hCLeQNGkr)bq zcTa>1R32bv_F?`7bNu@j92v z`l8yzhW7qnMoXqL9u8oW115)RouiKo*y%c3U!Xp?HC)*;s#de{#`Mk&>7CTA2M#+O z-lDTv({%Ojqbaa?pl7CLb}3=}LU4di?!BDea*vzjVF*~Jz*o@)l&bxPA+j_S9Sc1i1mNL1KbF+DpzfjGLEg>amgp`<$n!g7O z4LeaQ_RUh>s}RCYx$OlJQn!|$bLVPD--*{vpQI+h?4C}~Gx1;gI8Wwje*SIvS*|+b z+_%NP&ts`Imd$ovpY19!#akK43s0ZzjW~YHXt>bR%EUU~jvih;?c16eQEmU7MeJof z^WboQtFW)=rjF{W%KAZYk!{hVKXKI?j~2B3zA-y>Vk2Ys+x$bIIh+=~`}A3o^_cYJ z*cs``x!Xe%gH4XVECMy5dlp;A$GRB4rAw5@o#&gTq+ygRrWvWyvgA(Vcm<`KDWD4q zv*v8bMI($&@1F(>?b~)r@+DpDkIYy&_sDm#)8!F)_5R_i`a9T9_y-Brd#HHp-R|RP$5K=5!=8%Rhwf3P zi-s9`nd5!oHLl~^{uxe6{{e|s2R!i#lyJ{b!;(amr%(OSHT;>bZ99-&r>r+hFo<3l znQikfOl+GiwB3@a85rT-{}EH6s!s;@x5f<7&{#C~6I)Cbu%|n9YFpyu#nXQ$jl#tr z_p5xPdZ`=-Nsd?3^(M)Vps|ggWgCm=`}Vq*yKO=A8F(z%e>fX;+0%TeT(5Ip+U~YLLDMh=lygg!Ga*WQb=;t? z$L*}^jS)fC9c8xTPotG`y8)m#tzp;F{PTV3PxQJ6f!Y&GdP{anlN;hY?Zkk{hav^> zLLuNp$VPyk&Rc*UA?Xk&pu+@o37JD&tj}RUe_0Oza^ea2NRT)P43;7|f=Lkt$a1AI zKnE6s<-+h_y3=Gd7R!?XGF>I{Viwa81RaDTF)Y^_I|6|23EfpRlM{NYvY{54=Dj_T zm{@c;G!l;#{(&tB%U3@_g`@*-n__C99OXE^punoT8aw|K@;dqPft%e zgGFbtsDuR-OO@jyB~^}5UVyyB;X{}hg%voA$U!ZxC=N-+y~t#3pw(lAr%WLfu7;9h zD|rza(v>0wok?TRWitBfJTW{3S|j;dPb@T50ntMs3`s`C5MfSv9S~8t|4ra^PBLZr+gf(V6dJ|a$*L2_Kc=MoB<1eUP3G5y?J`2Kz_?wSZMbQI|zk|ts&BO4VTHGzoJ{Q=g_q+wXVfp^zX8k zXkadhi1cz8a7jU`yfR`w>=5vMLf_q#b0C@ofJXY2^MiFZqHE;VgEL)Go44AN4T`EP zs4c-k#>KST&6=a;Qx$1IIfMUXdufGPq$qdvcazVeHJe9^ckO70@?kEP)L%(Hre^b&aHEonE(xCqcjVkM=k!t!!_ zYC5O<+{b=NO*}I*EwN3!1%ohS1o1M#C?f>uWl-h-e){N^6(#a}zVj!^O0FWaMjoAI zlB6){5;Z5);}R31$7Q6++x`FBS0mBi=Txr=LdBzHy|zQ;CKNU->*K((3Wrek0Oy%v zes&)Q-bCLhYQ8|eBA@6YN^=FSz=Hm(eG{(jQj8)Dum3s32i>k78GhN>N&o-=07*qoM6N<$g1ch(GXMYp literal 0 HcmV?d00001 diff --git a/applications/system/hid_app/assets/Cmd_15x7.png b/applications/system/hid_app/assets/Cmd_15x7.png deleted file mode 100644 index a63a4be747a89745cbb32b5c9fb55d754f600dae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2426 zcmbtVdsGu=79So3iM+POA}pt*Ns))-i6kTqu|NWi-5{nsTv^1B3}k?0(##-1d9^^x z3RnxPRtt@fibYsq1q2#h1rb5^6xgQ15d`EVT@a)$LKR^r5rI9}?jJjIX6DYFdw=)d z-}l`+e+~%_vcfsy006KOyw4M1PaEtq-(ZH_yL0Sa0l?H63J3^E2nY&*6JgbdO0fhC z0u`VNl8A!*0l=rAAS_De6lTZ$s-b%8JKtyNN=pl^7rp;dlPK!SzB|4MR?GW5ixO-6 zjNxQQJvW-~>2@K1vAH+b`~mUF9#eDVQSV`n_qTs_C$#h1 z809B}i9cM;dX{mSe=niAH*4qT)zmb*0h9VC$30ZX?tf;h2^;A{b1TVE^-bF)umQ4| zAp%j_D>*9M47XVlcJPYRI9hgr*>!#EdEJRP+kq@~QX}Vf%M@>+mKI%%OG+0NTaMYh z1q=>(kg5*M5#Op3LLRy81rajFt)Fw}>&M=VHBOr%#X;=uPS&~DLw=r9dBZ>dF8n;V zIil?A zGMe%EP+zOCx9GN!=9ADjBX}DqHFDqC^Ek(G z+3E3fveWZF4o(gtoiG)>FGh*vDrQ)J~yofff5qK+n@ z2nw_2od`uEREM|E;tO5dK9uH5yVyIdy>A^OAkxPTUAhz_qDaHcyOKAa?ANjwC;f7; zrsL)g4b!%#qo*U`_R(&|UUr%yB2OC_uF>8>enQ`gbBrgUt#@@Ls*a_m=m*_Z(GQq= zEEmnwO)@5W!|S{!w*4a{(;Te?5}1K+!qAGaVgiJaGBQlnG1aqYG@ zDYF~~^8UVSaz>~6=~BD(P(D;rQ+x7Xhi{8I_1(EWmsvK06(*g}WbKU1xZ$hQKn1r{{Y0d8ZH^f* z_W3dEMq|WI$BuI6iP=cC!lfVRNxiyv>DluGX^%~G13>+$C6gr=^~Rf$JMGwj$Om@| zVueD$1CuuZCPuFVCYWS|oq!PyFvesKcF{kB08@h=02J60@RPzZAU;F}qc9?am3X>0 znTmI#Q|Vq*9~zS^C)4RHDxT&ojg`=8?s&YLP%MEIdSiD0Fg|6xf@X8dWJNaDBS$ge zkFkkGfkJnqyM=#XOJF%!tdB-k%awWqfTLz(q8voUc(puHfw0xS1cL<|ll5u}0dFut z6MPA~g(3I=SOwx4WGb0T;NtLjJVzysWs7)$%kJ2lFF}T)N;ZX(oSaNf_9DZoI0}u$ zVo|7c3Y|{EEJ#R-0u`%C3WWFqy^GhUgNro zyu$8ksfKoVu}k&zvIA707==}#Fr3K!KU&-n>A%3%WTD?P?42qI+Ztkh*KlbZ$~xV$ zJ%^%isWmP3qJIrqtbw^WEYiziz{SOuRSshFAymNg3*GEca5xVK*xH(wEG$tZI^C|J zL$f^%z2nt{Ga--b{~ecAmiV6MR}0tG@eKBfEez4@=ryZ5nJ0OpR!6h}7pY?r@<$Fc huhluV`!L-O&R7cBE}ON;j!OLi67Yk07yb8r@*g!;qu&4k diff --git a/applications/system/hid_app/assets/Cmd_17x10.png b/applications/system/hid_app/assets/Cmd_17x10.png new file mode 100644 index 0000000000000000000000000000000000000000..26ca3395c699cd19f2ae3c12d46954a45310eab7 GIT binary patch literal 556 zcmV+{0@MA8P)L%(Hre^b&aHEonE(xCqcjVkM=k!t!!_ zYC5O<+{b=NO*}I*EwN3!1%ohS1o1M#C?f>uWl-h-e){N^6(#a}zVj!^O0FWaMjoAI zlB6){5;Z5);}R31$7Q6++x`FBS0mBi=Txr=LdBzHy|zQ;CKNU->*K((3Wrek0Oy%v zes&)Q-bCLhYQ8n!+r=$Vtj3glk1^)H`0000501vCmP2ndL{yrdq5DkeKY1oo)gKX&HK%$+;;{_gMI z@4I*Y9vTw7oajgd0ARW3FTybVX^USLmge}qGsnRd0L*NlfPm1%fZzZ)2}V9rNu*#f zs00y68W!vi0KNqU5ixS72z&mwH5F^#`z1?PQc`H6_x?v^Qdmd!tr0y~q3H1}N~#p> zX&$?M5L)duIC~6o=i3YH>c8(V>NiB!yS}@vbUcrGq%!n~S(e*O`;*|q*Bq=yYrHCI zi>ebZwD$ZqTs)a^uNR%@UACv%GkRaIi>asMY3kkU0~J??wOTG#pWePay`8$|%e@|Z zSDXBCu;JpZ@kvr+Z|CFl(}sl6)1kp8xwmt=%6wbM10bMZdF5=(PBX#NCacc487uAk zNyVgr6_=}ksJFkfeQ>tzz*nr?*g#LWQ~7#rcdo@f%Hz#u7U+ZSFL~bI|KLt;4Q%!) z{U(HR{X*8$%yWUa6Sdu0>vvZ$((U^Q)sOdkAp7p@veQHi^@gT602oAi=ILOPyTLYiXPi&Q>vFi;2k@Va3+Nw(kJ_ z10K}!9n+L|%EgdJZfil5+~?}Axii(nZ^fIYPf!yeZf85^c>EUv&xyRjU*Cv4!PiEe z{BFPhvsmhR`$iYP&$kp?V@-_Y*+);dM;$z1IZ()PSmv1TLXWJP@^8wFs&YMM7kduN z+&$3KBw@M#*Jr1Wtz>L{Q@Dp@3#CPGJ$i!ZI3hnh za$J6R=0^WmUxWK^dfz{dOPJ~AqMSks|PHKBxQ*m-q%BPoJLeS+-k{>rv1 zA86QiU2R=$i7k6Om0P&!%BZ~Bph!*aP4qtYUV`H`D%NyMcMxeaG{oNPERVg%-fXS6 z$RK2nc1ND~9$ou$Br*L*I9eP0&@V*BKTeHEl2jZ$vdKI0iK%ldkY1y%wM;ONo*kNQ zURRjdJYDF#I&-jhh=1o7RD)8o%ys8ol4^UAucU8Z7tt^U4trX zRbSpu8^)$|$o;deHUs(4!OE&{{{6+}=Apqj;u)65Th@0k9daA}airF%qr|3azx*yx z{t3&s0T$_>IdrEU2T_f=@2u zM%Lx}sP&F*rOu;|qSZ>5UZ5-O!WP5RXFJj#5_Ek)^&tbn;G$l3MS8Op9}xNAMp3+2 z40zzOB|tD)0T6J>1U~^2CSZ!oJp5wqf&jBQJpd^2Cm@i)aUdyF4r4GXhgBq&H;qAZ zV=-7>3|}Ujrl7G{90rN$EsK}3nC>K!n^+=+ltyEB05Cmdx`1YTh_E1A7?ESx@Td61 zqC?>uv5n%ta;30>CNV~%sTC@t0l-spaZv$c5|Ubxq(r%DKk}Rf7nhA{I+-+Qf+hNq zH;O|^0WboRd}s_BgUlzANF*L2i|2+3gXZ1wH$So*!&F>4JtZZDmf}T&kpw!E!{N{w zEINxt#Vx34suGi^sY;ac9OMO#5JaU2q{1LrNiyO};^1V=k4!cOS~%u;DpX?eLMSCV zpBJ7XT`f`3nKTAnp`gFY6UD;7MUt=dM8i{6AUzC3;bcS#;^vfB0pW%F-vnOeghBDI z32yu{$9thBc*;CHh*-=O!qQ{~sKi7k$aw8WLmI@R>aNOS*Y`9^KedOIqxC|ITUg z2Idp-NH2x~pLi|e*bRI>M2m!i@V8gx>=vxJM6x9084PH0_rF5MbS?FO2pDzR5MjZ* zwk&l7d}deg9ccNd!iI}=F85dO%9S@&l&}v#b~bM?zl!cVm9q)ib$xhxQ?%EK84a&h c-wD*%=rG#yo8xYw#yKPk3=y98-}>2q0D4cRIRF3v diff --git a/applications/system/hid_app/assets/Ctrl_17x10.png b/applications/system/hid_app/assets/Ctrl_17x10.png new file mode 100644 index 0000000000000000000000000000000000000000..0eda72160009907c74a5f44e2dd90cd923f1fdfb GIT binary patch literal 552 zcmV+@0@wYCP)L%(Hre^b&aHEonE(xCqcjVkM=k!t!!_ zYC5O<+{b=NO*}I*EwN3!1%ohS1o1M#C?f>uWl-h-e){N^6(#a}zVj!^O0FWaMjoAI zlB6){5;Z5);}R31$7Q6++x`FBS0mBi=Txr=LdBzHy|zQ;CKNU->*K((3Wrek0Oy%v zes&)Q-bCLhYQ8xs5R007ntcL;*T1E?xm8=0AOSR^Z7w>e1AR?kD%|VBvQy9 zQbH&!4fgi|09IaJXq0?Ys5S5J)n!{Z|CG^LRFrQq@BU?Zd~iqRtAM6VKY)s_wgif`Ns|I)}IS72nUHoGK4GWt8DK(?08e@?SP)W7V!@ zH3e01S6h33A1RznyVs|l=v#NF$|dqhpS_`r?FGu+p9jlsjOcV6tS+^EeQG;p>*t4^ z4{tH}^HBY@TlXiy#=fq{m!}tE$1Vi<8)VMmimkOm=Oe#7-kQ3s5?pEQ|uMbDV& zw#65MgReGJ0O4aI^2t8U!=li*R2+yYS?Uw z3`Et`W}(C>o=zJ2LG7kd?A&?Jjvuz3?K~E1)t{kBsN=RYP6*~I7~(==LRxU4`H1CP zz`&q0rF8!^`K?kB?3~@27cTd>@muyx)yV5HhN%;jSeVn*&OQ_KnYYVC&d_gv3Omcw zg`fN8sLxX|<+637z1PQk3eB-5dcxeJ*~IYU$4m$F**5EJbM0wi6;nP<>ERU)-&%<) zvGjw3y-lK?f))eqHLdO4paQ#s`+wuc81Jul`h6a_9I|h|X>7EE?o+fte$alteo`Jvt~F0fmKP_qo5iTeoeUvO zn4dATiBvF5-}v@vFyEp1Jz1`-gR|4Z{l*cJTK2HIqchon9IW-ssm&Qp@@|}um3=i( z-gbSb*3+uHt-CF*<#3mB4<}U_o>Su&rmeZD{uSFCYrBtvHQnkwjLxr-)PBc-GtN zRT&%mbN>16_*5tQ>!ntU!Cd%wdBxZN{;Z*Scqp29k?H)p`Q0B*IF4Nzt=ZI3WKnTc zeitbHfXS*yg!4~rdXmpTYOOJA&SBg1?n<`hKnbD!iM-Y0Kc1EIfI-KlLG@vmdBBu|Qa`*Q~oPz1fNnh+HT_ z7$Xt^&bVv}5DZ=g2)JZ`pMU`aFw~C_{9=9r14fH_08rvjz*~kyLtu~`!4S0^QGrZ% zDjjrW(wVMw7Q>UOpfZ_kI>>OB#YmY9ClGWLNu;n+Z|npBh9?Y{(acW}mSqz?vc>mq zuiz7l28Tpo5u$fEQba+O=%Z0J3YFdf;A%LysDLmDs8Pf#)f|l%Y0-j%%X&491TLCj zabBbdQ4q*SPzdy((y4S3j|hSw7nQ|uf(3p{?)aM*NseJE4vm(SltfK(r6Oo7jlpKK zX>=xy$)w;G6m_x^lV~VPHTfCHa~uJrmZGoAzP zIOZk6^~q?|AvW>%nwBri_55z zplV28QZLf;ny$`KpXTDCaNxCkJiX~`7Tufmaz1NZSNN$a$P}QuI@^z zi|z1im+H&Q;iHfQL(mWeiRb+vExs7(zra?p(C-;eAPVDKL!$2*9)n9;qg%4)()2C0 zs>Po5@1hoOU>*^V^n4ibh&vkWJn{LkODOOTd1GVN!44t-niAY+7sQnTK`9ZNcc54D zdVd^D3=VgLXD diff --git a/applications/system/hid_app/assets/Del_17x10.png b/applications/system/hid_app/assets/Del_17x10.png new file mode 100644 index 0000000000000000000000000000000000000000..13d736983079f920184d157d83054efe809a6981 GIT binary patch literal 551 zcmV+?0@(eDP)L%(Hre^b&aHEonE(xCqcjVkM=k!t!!_ zYC5O<+{b=NO*}I*EwN3!1%ohS1o1M#C?f>uWl-h-e){N^6(#a}zVj!^O0FWaMjoAI zlB6){5;Z5);}R31$7Q6++x`FBS0mBi=Txr=LdBzHy|zQ;CKNU->*K((3Wrek0Oy%v zes&)Q-bCLhYQ8Askdnas~hZ002ovPDHLkV1h}~`Pcve literal 0 HcmV?d00001 diff --git a/applications/system/hid_app/assets/Esc_14x7.png b/applications/system/hid_app/assets/Esc_14x7.png deleted file mode 100644 index 3be4691d8a3d050bf14f5bd29099705d984eead7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2430 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 literal 0 HcmV?d00001 diff --git a/applications/system/hid_app/views/hid_keyboard.c b/applications/system/hid_app/views/hid_keyboard.c index 17ff754f52c..9060c1d6a64 100644 --- a/applications/system/hid_app/views/hid_keyboard.c +++ b/applications/system/hid_app/views/hid_keyboard.c @@ -49,7 +49,7 @@ typedef struct { #define ROW_COUNT 7 #define COLUMN_COUNT 12 -// 0 width items are not drawn, but there value is used +// 0 width items are not drawn, but their value is used const HidKeyboardKey hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = { { {.width = 1, .icon = &I_ButtonF1_5x8, .value = HID_KEYBOARD_F1}, @@ -140,17 +140,17 @@ const HidKeyboardKey hid_keyboard_keyset[ROW_COUNT][COLUMN_COUNT] = { {.width = 1, .icon = &I_ButtonRight_4x7, .value = HID_KEYBOARD_RIGHT_ARROW}, }, { - {.width = 2, .icon = &I_Ctrl_15x7, .value = HID_KEYBOARD_L_CTRL}, + {.width = 2, .icon = &I_Ctrl_17x10, .value = HID_KEYBOARD_L_CTRL}, {.width = 0, .value = HID_KEYBOARD_L_CTRL}, - {.width = 2, .icon = &I_Alt_11x7, .value = HID_KEYBOARD_L_ALT}, + {.width = 2, .icon = &I_Alt_17x10, .value = HID_KEYBOARD_L_ALT}, {.width = 0, .value = HID_KEYBOARD_L_ALT}, - {.width = 2, .icon = &I_Cmd_15x7, .value = HID_KEYBOARD_L_GUI}, + {.width = 2, .icon = &I_Cmd_17x10, .value = HID_KEYBOARD_L_GUI}, {.width = 0, .value = HID_KEYBOARD_L_GUI}, - {.width = 2, .icon = &I_Tab_15x7, .value = HID_KEYBOARD_TAB}, + {.width = 2, .icon = &I_Tab_17x10, .value = HID_KEYBOARD_TAB}, {.width = 0, .value = HID_KEYBOARD_TAB}, - {.width = 2, .icon = &I_Esc_14x7, .value = HID_KEYBOARD_ESCAPE}, + {.width = 2, .icon = &I_Esc_17x10, .value = HID_KEYBOARD_ESCAPE}, {.width = 0, .value = HID_KEYBOARD_ESCAPE}, - {.width = 2, .icon = &I_Del_12x7, .value = HID_KEYBOARD_DELETE_FORWARD}, + {.width = 2, .icon = &I_Del_17x10, .value = HID_KEYBOARD_DELETE_FORWARD}, {.width = 0, .value = HID_KEYBOARD_DELETE_FORWARD}, }, }; From 04cead1fc56d4093bffee8d3a4a7b47fba93061f Mon Sep 17 00:00:00 2001 From: Astra <93453568+Astrrra@users.noreply.github.com> Date: Sat, 2 Dec 2023 09:03:10 +0400 Subject: [PATCH 10/14] [FL-3620] Add the "remove pairing" button to BLE hid (#3237) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- applications/system/hid_app/hid.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/applications/system/hid_app/hid.c b/applications/system/hid_app/hid.c index a42fc609178..88a68f09d0f 100644 --- a/applications/system/hid_app/hid.c +++ b/applications/system/hid_app/hid.c @@ -14,8 +14,22 @@ enum HidDebugSubmenuIndex { HidSubmenuIndexMouse, HidSubmenuIndexMouseClicker, HidSubmenuIndexMouseJiggler, + HidSubmenuIndexRemovePairing, }; +static void bt_hid_remove_pairing(Bt* bt) { + bt_disconnect(bt); + + // Wait 2nd core to update nvm storage + furi_delay_ms(200); + + furi_hal_bt_stop_advertising(); + + bt_forget_bonded_devices(bt); + + furi_hal_bt_start_advertising(); +} + static void hid_submenu_callback(void* context, uint32_t index) { furi_assert(context); Hid* app = context; @@ -45,6 +59,8 @@ static void hid_submenu_callback(void* context, uint32_t index) { } else if(index == HidSubmenuIndexMouseJiggler) { app->view_id = HidViewMouseJiggler; view_dispatcher_switch_to_view(app->view_dispatcher, HidViewMouseJiggler); + } else if(index == HidSubmenuIndexRemovePairing) { + bt_hid_remove_pairing(app->bt); } } @@ -143,6 +159,14 @@ Hid* hid_alloc(HidTransport transport) { HidSubmenuIndexMouseJiggler, hid_submenu_callback, app); + if(transport == HidTransportBle) { + submenu_add_item( + app->device_type_submenu, + "Remove Pairing", + HidSubmenuIndexRemovePairing, + hid_submenu_callback, + app); + } view_set_previous_callback(submenu_get_view(app->device_type_submenu), hid_exit); view_dispatcher_add_view( app->view_dispatcher, HidViewSubmenu, submenu_get_view(app->device_type_submenu)); From c6a14e1a6779ded87b848b06b2cbc51a147f96b3 Mon Sep 17 00:00:00 2001 From: pborsutzki Date: Sat, 2 Dec 2023 08:27:58 +0100 Subject: [PATCH 11/14] Fixed a zero allocation error when reading an iso15693 nfc tag with no additional blocks. (#3229) Co-authored-by: gornekich --- .../iso15693_3/iso15693_3_poller_i.c | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c index 917f7dbb8e0..ca6f5435e3e 100644 --- a/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c +++ b/lib/nfc/protocols/iso15693_3/iso15693_3_poller_i.c @@ -108,28 +108,30 @@ Iso15693_3Error iso15693_3_poller_activate(Iso15693_3Poller* instance, Iso15693_ break; } - // Read blocks: Optional command - simple_array_init(data->block_data, system_info->block_count * system_info->block_size); - ret = iso15693_3_poller_read_blocks( - instance, - simple_array_get_data(data->block_data), - system_info->block_count, - system_info->block_size); - if(ret != Iso15693_3ErrorNone) { - ret = iso15693_3_poller_filter_error(ret); - break; - } - - // Get block security status: Optional command - simple_array_init(data->block_security, system_info->block_count); - - ret = iso15693_3_poller_get_blocks_security( - instance, simple_array_get_data(data->block_security), system_info->block_count); - if(ret != Iso15693_3ErrorNone) { - ret = iso15693_3_poller_filter_error(ret); - break; + if(system_info->block_count > 0) { + // Read blocks: Optional command + simple_array_init( + data->block_data, system_info->block_count * system_info->block_size); + ret = iso15693_3_poller_read_blocks( + instance, + simple_array_get_data(data->block_data), + system_info->block_count, + system_info->block_size); + if(ret != Iso15693_3ErrorNone) { + ret = iso15693_3_poller_filter_error(ret); + break; + } + + // Get block security status: Optional command + simple_array_init(data->block_security, system_info->block_count); + + ret = iso15693_3_poller_get_blocks_security( + instance, simple_array_get_data(data->block_security), system_info->block_count); + if(ret != Iso15693_3ErrorNone) { + ret = iso15693_3_poller_filter_error(ret); + break; + } } - } while(false); return ret; From eb6fe0a4dbe2e6d3776483e6a191de2307b0060e Mon Sep 17 00:00:00 2001 From: Skorpionm <85568270+Skorpionm@users.noreply.github.com> Date: Sat, 2 Dec 2023 11:34:02 +0400 Subject: [PATCH 12/14] SubGhz: fix count bit for detect gate_tx protocol (#3253) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- lib/subghz/protocols/gate_tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/subghz/protocols/gate_tx.c b/lib/subghz/protocols/gate_tx.c index 51a424fed94..2ebd6bb03b9 100644 --- a/lib/subghz/protocols/gate_tx.c +++ b/lib/subghz/protocols/gate_tx.c @@ -227,7 +227,7 @@ void subghz_protocol_decoder_gate_tx_feed(void* context, bool level, uint32_t du if(duration >= ((uint32_t)subghz_protocol_gate_tx_const.te_short * 10 + subghz_protocol_gate_tx_const.te_delta)) { instance->decoder.parser_step = GateTXDecoderStepFoundStartBit; - if(instance->decoder.decode_count_bit >= + if(instance->decoder.decode_count_bit == subghz_protocol_gate_tx_const.min_count_bit_for_found) { instance->generic.data = instance->decoder.decode_data; instance->generic.data_count_bit = instance->decoder.decode_count_bit; From c477d1321af5a25df57d1cbbf709c9853f768f78 Mon Sep 17 00:00:00 2001 From: Honghao Zeng Date: Sun, 3 Dec 2023 20:00:46 +0900 Subject: [PATCH 13/14] nfc: m1k-based Aime (non-AIC) card support (#3241) Co-authored-by: gornekich --- applications/main/nfc/application.fam | 9 + .../main/nfc/plugins/supported_cards/aime.c | 164 ++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 applications/main/nfc/plugins/supported_cards/aime.c diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index 9a98b57c8c3..07e97c0c9ce 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -74,6 +74,15 @@ App( sources=["plugins/supported_cards/two_cities.c"], ) +App( + appid="aime_parser", + apptype=FlipperAppType.PLUGIN, + entry_point="aime_plugin_ep", + targets=["f7"], + requires=["nfc"], + sources=["plugins/supported_cards/aime.c"], +) + App( appid="nfc_start", targets=["f7"], diff --git a/applications/main/nfc/plugins/supported_cards/aime.c b/applications/main/nfc/plugins/supported_cards/aime.c new file mode 100644 index 00000000000..1db89ffd637 --- /dev/null +++ b/applications/main/nfc/plugins/supported_cards/aime.c @@ -0,0 +1,164 @@ +#include "nfc_supported_card_plugin.h" + +#include + +#include +#include +#include + +#define TAG "Aime" + +static const uint64_t aime_key = 0x574343467632; + +bool aime_verify(Nfc* nfc) { + bool verified = false; + + do { + const uint8_t verify_sector = 0; + uint8_t block_num = mf_classic_get_first_block_num_of_sector(verify_sector); + FURI_LOG_D(TAG, "Verifying sector %u", verify_sector); + + MfClassicKey key = {}; + nfc_util_num2bytes(aime_key, COUNT_OF(key.data), key.data); + + MfClassicAuthContext auth_ctx = {}; + MfClassicError error = + mf_classic_poller_sync_auth(nfc, block_num, &key, MfClassicKeyTypeA, &auth_ctx); + + if(error != MfClassicErrorNone) { + FURI_LOG_D(TAG, "Failed to read block %u: %d", block_num, error); + break; + } + + verified = true; + } while(false); + + return verified; +} + +static bool aime_read(Nfc* nfc, NfcDevice* device) { + furi_assert(nfc); + furi_assert(device); + + bool is_read = false; + + MfClassicData* data = mf_classic_alloc(); + nfc_device_copy_data(device, NfcProtocolMfClassic, data); + + do { + MfClassicType type = MfClassicType1k; + MfClassicError error = mf_classic_poller_sync_detect_type(nfc, &type); + if(error != MfClassicErrorNone) break; + + data->type = type; + MfClassicDeviceKeys keys = {}; + for(size_t i = 0; i < mf_classic_get_total_sectors_num(data->type); i++) { + nfc_util_num2bytes(aime_key, sizeof(MfClassicKey), keys.key_a[i].data); + FURI_BIT_SET(keys.key_a_mask, i); + nfc_util_num2bytes(aime_key, sizeof(MfClassicKey), keys.key_b[i].data); + FURI_BIT_SET(keys.key_b_mask, i); + } + + error = mf_classic_poller_sync_read(nfc, &keys, data); + if(error != MfClassicErrorNone) { + FURI_LOG_W(TAG, "Failed to read data"); + break; + } + + nfc_device_set_data(device, NfcProtocolMfClassic, data); + + is_read = true; + } while(false); + + mf_classic_free(data); + + return is_read; +} + +static bool aime_parse(const NfcDevice* device, FuriString* parsed_data) { + furi_assert(device); + + const MfClassicData* data = nfc_device_get_data(device, NfcProtocolMfClassic); + + bool parsed = false; + + do { + // verify key + MfClassicSectorTrailer* sec_tr = mf_classic_get_sector_trailer_by_sector(data, 0); + uint64_t key = nfc_util_bytes2num(sec_tr->key_a.data, 6); + if(key != aime_key) break; + + // Aime Magic is stored at block 1, starts from byte 0, len 4 bytes + const uint8_t* aime_magic = &data->block[1].data[0]; + + // verify aime magic + if(aime_magic[0] != 'S' || aime_magic[1] != 'B' || aime_magic[2] != 'S' || + aime_magic[3] != 'D') + break; + + // Aime checksum is stored at block 1, starts from byte 13, len 3 bytes + // seems like only old games checks this? e.g., old versions of Chunithm + const uint8_t* aime_checksum = &data->block[1].data[13]; + + // Aime access code is stored as decimal hex representation in block 2, starts from byte 6, len 10 bytes + const uint8_t* aime_accesscode = &data->block[2].data[6]; + + char aime_accesscode_str[24 + 1]; + snprintf( + aime_accesscode_str, + sizeof(aime_accesscode_str), + "%02x%02x %02x%02x %02x%02x %02x%02x %02x%02x", + aime_accesscode[0], + aime_accesscode[1], + aime_accesscode[2], + aime_accesscode[3], + aime_accesscode[4], + aime_accesscode[5], + aime_accesscode[6], + aime_accesscode[7], + aime_accesscode[8], + aime_accesscode[9]); + + // validate decimal hex representation + for(int i = 0; i < 24; i++) { + if(aime_accesscode_str[i] == ' ') continue; + if(aime_accesscode_str[i] < '0' || aime_accesscode_str[i] > '9') return false; + } + + // Note: Aime access code has some other self-check algorithms that are not public. + // This parser does not try to verify the number. + + furi_string_printf( + parsed_data, + "\e#Aime Card\nAccess Code: \n%s\nChecksum: %02X%02X%02X\n", + aime_accesscode_str, + aime_checksum[0], + aime_checksum[1], + aime_checksum[2]); + + parsed = true; + + } while(false); + + return parsed; +} + +/* Actual implementation of app<>plugin interface */ +static const NfcSupportedCardsPlugin aime_plugin = { + .protocol = NfcProtocolMfClassic, + .verify = aime_verify, + .read = aime_read, + .parse = aime_parse, +}; + +/* Plugin descriptor to comply with basic plugin specification */ +static const FlipperAppPluginDescriptor aime_plugin_descriptor = { + .appid = NFC_SUPPORTED_CARD_PLUGIN_APP_ID, + .ep_api_version = NFC_SUPPORTED_CARD_PLUGIN_API_VERSION, + .entry_point = &aime_plugin, +}; + +/* Plugin entry point - must return a pointer to const descriptor */ +const FlipperAppPluginDescriptor* aime_plugin_ep() { + return &aime_plugin_descriptor; +} From 82baf1e9232ad72b565cfe33e6b5177a32daa4fe Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 5 Dec 2023 17:40:06 +0400 Subject: [PATCH 14/14] [FL-3701] NFC fixes (#3264) * nfc app: fix unlock with manual password crash * nfc app: preserve card detected state * nfc app: fix mf keys scene switch * nfc app: fix multiple protocol tag detect notification * nfc plugin: fix retrun in function body in aime parser * iso14443-3b poller: rework ATTRIB response check * nfc app: fix navigation after file load failur * iso14443-3b poller: fix PVS warning * mfc listener: add crutch in mfc emulation --- applications/main/nfc/nfc_app.c | 19 ++++++++++--------- .../main/nfc/plugins/supported_cards/aime.c | 7 ++++++- .../main/nfc/scenes/nfc_scene_detect.c | 1 + .../main/nfc/scenes/nfc_scene_extra_actions.c | 6 +----- .../nfc_scene_mf_ultralight_unlock_warn.c | 3 ++- .../nfc/scenes/nfc_scene_select_protocol.c | 1 - applications/main/nfc/views/dict_attack.c | 1 - .../iso14443_3b/iso14443_3b_poller_i.c | 15 ++++++++++++--- .../mf_classic/mf_classic_listener.c | 7 +++++++ 9 files changed, 39 insertions(+), 21 deletions(-) diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 141a67e5cba..5ae0ca5f572 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -400,15 +400,16 @@ bool nfc_load_from_file_select(NfcApp* instance) { browser_options.base_path = NFC_APP_FOLDER; browser_options.hide_dot_files = true; - // Input events and views are managed by file_browser - bool result = dialog_file_browser_show( - instance->dialogs, instance->file_path, instance->file_path, &browser_options); - - if(result) { - result = nfc_load_file(instance, instance->file_path, true); - } - - return result; + bool success = false; + do { + // Input events and views are managed by file_browser + if(!dialog_file_browser_show( + instance->dialogs, instance->file_path, instance->file_path, &browser_options)) + break; + success = nfc_load_file(instance, instance->file_path, true); + } while(!success); + + return success; } void nfc_show_loading_popup(void* context, bool show) { diff --git a/applications/main/nfc/plugins/supported_cards/aime.c b/applications/main/nfc/plugins/supported_cards/aime.c index 1db89ffd637..df1e7e0772f 100644 --- a/applications/main/nfc/plugins/supported_cards/aime.c +++ b/applications/main/nfc/plugins/supported_cards/aime.c @@ -120,10 +120,15 @@ static bool aime_parse(const NfcDevice* device, FuriString* parsed_data) { aime_accesscode[9]); // validate decimal hex representation + bool code_is_hex = true; for(int i = 0; i < 24; i++) { if(aime_accesscode_str[i] == ' ') continue; - if(aime_accesscode_str[i] < '0' || aime_accesscode_str[i] > '9') return false; + if(aime_accesscode_str[i] < '0' || aime_accesscode_str[i] > '9') { + code_is_hex = false; + break; + } } + if(!code_is_hex) break; // Note: Aime access code has some other self-check algorithms that are not public. // This parser does not try to verify the number. diff --git a/applications/main/nfc/scenes/nfc_scene_detect.c b/applications/main/nfc/scenes/nfc_scene_detect.c index 326b1458c0d..593c67aabe1 100644 --- a/applications/main/nfc/scenes/nfc_scene_detect.c +++ b/applications/main/nfc/scenes/nfc_scene_detect.c @@ -37,6 +37,7 @@ bool nfc_scene_detect_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventWorkerExit) { if(instance->protocols_detected_num > 1) { + notification_message(instance->notifications, &sequence_single_vibro); scene_manager_next_scene(instance->scene_manager, NfcSceneSelectProtocol); } else { scene_manager_next_scene(instance->scene_manager, NfcSceneRead); diff --git a/applications/main/nfc/scenes/nfc_scene_extra_actions.c b/applications/main/nfc/scenes/nfc_scene_extra_actions.c index 7f51b717415..721919d2b1a 100644 --- a/applications/main/nfc/scenes/nfc_scene_extra_actions.c +++ b/applications/main/nfc/scenes/nfc_scene_extra_actions.c @@ -45,11 +45,7 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexMfClassicKeys) { - if(nfc_dict_check_presence(NFC_APP_MF_CLASSIC_DICT_USER_PATH)) { - scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicKeys); - } else { - scene_manager_previous_scene(instance->scene_manager); - } + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicKeys); consumed = true; } else if(event.event == SubmenuIndexMfUltralightUnlock) { mf_ultralight_auth_reset(instance->mf_ul_auth); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c index 6be051cedd8..e3bbfba59aa 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c @@ -52,11 +52,12 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve bool consumed = false; - nfc->protocols_detected[0] = nfc_device_get_protocol(nfc->nfc_device); MfUltralightAuthType type = nfc->mf_ul_auth->type; if((type == MfUltralightAuthTypeReader) || (type == MfUltralightAuthTypeManual)) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultRight) { + const NfcProtocol mfu_protocol[] = {NfcProtocolMfUltralight}; + nfc_app_set_detected_protocols(nfc, mfu_protocol, COUNT_OF(mfu_protocol)); scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); dolphin_deed(DolphinDeedNfcRead); consumed = true; diff --git a/applications/main/nfc/scenes/nfc_scene_select_protocol.c b/applications/main/nfc/scenes/nfc_scene_select_protocol.c index 86b9982fc69..7a5d1252182 100644 --- a/applications/main/nfc/scenes/nfc_scene_select_protocol.c +++ b/applications/main/nfc/scenes/nfc_scene_select_protocol.c @@ -21,7 +21,6 @@ void nfc_scene_select_protocol_on_enter(void* context) { } else { prefix = "Read as"; submenu_set_header(submenu, "Multi-protocol card"); - notification_message(instance->notifications, &sequence_single_vibro); } for(uint32_t i = 0; i < instance->protocols_detected_num; i++) { diff --git a/applications/main/nfc/views/dict_attack.c b/applications/main/nfc/views/dict_attack.c index b656c2dc5b5..ce867908838 100644 --- a/applications/main/nfc/views/dict_attack.c +++ b/applications/main/nfc/views/dict_attack.c @@ -125,7 +125,6 @@ void dict_attack_reset(DictAttack* instance) { instance->view, DictAttackViewModel * model, { - model->card_detected = false; model->sectors_total = 0; model->sectors_read = 0; model->current_sector = 0; diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c index 1ee5237c641..15fc609dbc2 100644 --- a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c @@ -131,9 +131,18 @@ Iso14443_3bError iso14443_3b_poller_activate(Iso14443_3bPoller* instance, Iso144 break; } - if(bit_buffer_get_size_bytes(instance->rx_buffer) != 1 || - bit_buffer_get_byte(instance->rx_buffer, 0) != 0) { - FURI_LOG_D(TAG, "Unexpected ATTRIB response"); + if(bit_buffer_get_size_bytes(instance->rx_buffer) != 1) { + FURI_LOG_W( + TAG, + "Unexpected ATTRIB response length: %zu", + bit_buffer_get_size_bytes(instance->rx_buffer)); + } + + if(bit_buffer_get_byte(instance->rx_buffer, 0) != 0) { + FURI_LOG_D( + TAG, + "Incorrect CID in ATTRIB response: %02X", + bit_buffer_get_byte(instance->rx_buffer, 0)); instance->state = Iso14443_3bPollerStateActivationFailed; ret = Iso14443_3bErrorCommunication; break; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener.c b/lib/nfc/protocols/mf_classic/mf_classic_listener.c index fb12ba8a95c..3423e89e4bd 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_listener.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener.c @@ -481,6 +481,13 @@ static const MfClassicListenerCmd mf_classic_listener_cmd_handlers[] = { .command_num = COUNT_OF(mf_classic_listener_halt_handlers), .handler = mf_classic_listener_halt_handlers, }, + { + // This crutch is necessary since some devices (like Pixel) send 15-bit "HALT" command ... + .cmd_start_byte = MF_CLASSIC_CMD_HALT_MSB, + .cmd_len_bits = 15, + .command_num = COUNT_OF(mf_classic_listener_halt_handlers), + .handler = mf_classic_listener_halt_handlers, + }, { .cmd_start_byte = MF_CLASSIC_CMD_AUTH_KEY_A, .cmd_len_bits = 2 * 8,