diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum.h b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum.h index 5ead8cc6f..b6d6f1c1f 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum.h +++ b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum.h @@ -13,68 +13,8 @@ // limitations under the License. #pragma once -#include_next "mbedtls/bignum.h" -#include "sdkconfig.h" - -/** - * This is a wrapper for the main mbedtls/bignum.h. This wrapper - * provides a few additional ESP32-only functions. - * - * This is because we don't set MBEDTLS_BIGNUM_ALT in the same way we - * do for AES, SHA, etc. Because we still use most of the bignum.h - * implementation and just replace a few hardware accelerated - * functions (see MBEDTLS_MPI_EXP_MOD_ALT & MBEDTLS_MPI_MUL_MPI_ALT in - * esp_config.h). - * - * @note Unlike the other hardware accelerator support functions in esp32/hwcrypto, there is no - * generic "hwcrypto/bignum.h" header for using these functions without mbedTLS. The reason for this - * is that all of the function implementations depend strongly upon the mbedTLS MPI implementation. - */ - -/** - * @brief Lock access to RSA Accelerator (MPI/bignum operations) - * - * RSA Accelerator hardware unit can only be used by one - * consumer at a time. - * - * @note This function is non-recursive (do not call it twice from the - * same task.) - * - * @note You do not need to call this if you are using the mbedTLS bignum.h - * API or esp_mpi_xxx functions. This function is only needed if you - * want to call ROM RSA functions or access the registers directly. - * - */ -void esp_mpi_acquire_hardware(void); - -/** - * @brief Unlock access to RSA Accelerator (MPI/bignum operations) - * - * Has to be called once for each call to esp_mpi_acquire_hardware(). - * - * @note You do not need to call this if you are using the mbedTLS bignum.h - * API or esp_mpi_xxx functions. This function is only needed if you - * want to call ROM RSA functions or access the registers directly. - */ -void esp_mpi_release_hardware(void); - -//#if CONFIG_MBEDTLS_HARDWARE_MPI - -/* @brief MPI modular mupltiplication function - * - * Calculates Z = (X * Y) mod M using MPI hardware acceleration. - * - * This is not part of the standard mbedTLS bignum API. - * - * @note All of X, Y & Z should be less than 4096 bit long or an error is returned. - * - * @param Z Result bignum, should be pre-initialised with mbedtls_mpi_init(). - * @param X First multiplication argument. - * @param Y Second multiplication argument. - * @param M Modulus value for result. - * - * @return 0 on success, mbedTLS MPI error codes on failure. - */ -int esp_mpi_mul_mpi_mod(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M); - -//#endif // CONFIG_MBEDTLS_HARDWARE_MPI +#if CONFIG_IDF_TARGET_ESP32 +#include "bignum_ESP32.h" +#elif CONFIG_IDF_TARGET_ESP32C3 +#include "bignum_ESP32_C3.h" +#endif diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32.c b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32.c new file mode 100644 index 000000000..1a63ffe7f --- /dev/null +++ b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32.c @@ -0,0 +1,291 @@ +/** + * \brief Multi-precision integer library, ESP-IDF hardware accelerated parts + * + * based on mbedTLS implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * Additions Copyright (C) 2016-2020, Espressif Systems (Shanghai) PTE Ltd + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#if CONFIG_IDF_TARGET_ESP32 +#if __has_include("esp_idf_version.h") +#include "esp_idf_version.h" +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) +#warning("IDF is 4 or later") +#include "soc/hwcrypto_periph.h" +#endif +#endif + +#include "soc/hwcrypto_reg.h" +#include "driver/periph_ctrl.h" +#include +#include "bignum_impl.h" +#include +#include +#if CONFIG_IDF_TARGET_ESP32C3 +#include "esp32c3/dport_access.h" +#endif + +static _lock_t mpi_lock; + +/* Round up number of words to nearest + 512 bit (16 word) block count. +*/ +size_t esp_mpi_hardware_words(size_t words) +{ + return (words + 0xF) & ~0xF; +} + +void esp_mpi_enable_hardware_hw_op( void ) +{ + /* newlib locks lazy initialize on ESP-IDF */ + _lock_acquire(&mpi_lock); + + /* Enable RSA hardware */ + periph_module_enable(PERIPH_RSA_MODULE); + DPORT_REG_CLR_BIT(DPORT_RSA_PD_CTRL_REG, DPORT_RSA_PD); + + while (DPORT_REG_READ(RSA_CLEAN_REG) != 1) + { } + // Note: from enabling RSA clock to here takes about 1.3us +} + +void esp_mpi_disable_hardware_hw_op( void ) +{ + DPORT_REG_SET_BIT(DPORT_RSA_PD_CTRL_REG, DPORT_RSA_PD); + + /* Disable RSA hardware */ + periph_module_disable(PERIPH_RSA_MODULE); + + _lock_release(&mpi_lock); +} + + +/* Copy mbedTLS MPI bignum 'mpi' to hardware memory block at 'mem_base'. + + If hw_words is higher than the number of words in the bignum then + these additional words will be zeroed in the memory buffer. + +*/ +static inline void mpi_to_mem_block(uint32_t mem_base, const mbedtls_mpi *mpi, size_t hw_words) +{ + uint32_t *pbase = (uint32_t *)mem_base; + uint32_t copy_words = MIN(hw_words, mpi->n); + + /* Copy MPI data to memory block registers */ + for (int i = 0; i < copy_words; i++) { + pbase[i] = mpi->p[i]; + } + + /* Zero any remaining memory block data */ + for (int i = copy_words; i < hw_words; i++) { + pbase[i] = 0; + } +} + +/* Read mbedTLS MPI bignum back from hardware memory block. + + Reads num_words words from block. + + Bignum 'x' should already be grown to at least num_words by caller (can be done while + calculation is in progress, to save some cycles) +*/ +static inline void mem_block_to_mpi(mbedtls_mpi *x, uint32_t mem_base, int num_words) +{ + assert(x->n >= num_words); + + /* Copy data from memory block registers */ + esp_dport_access_read_buffer(x->p, mem_base, num_words); + + /* Zero any remaining limbs in the bignum, if the buffer is bigger + than num_words */ + for (size_t i = num_words; i < x->n; i++) { + x->p[i] = 0; + } +} + + +/* Begin an RSA operation. op_reg specifies which 'START' register + to write to. +*/ +static inline void start_op(uint32_t op_reg) +{ + /* Clear interrupt status */ + DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1); + + /* Note: above REG_WRITE includes a memw, so we know any writes + to the memory blocks are also complete. */ + + DPORT_REG_WRITE(op_reg, 1); +} + +/* Wait for an RSA operation to complete. +*/ +static inline void wait_op_complete(void) +{ + while (DPORT_REG_READ(RSA_INTERRUPT_REG) != 1) + { } + + /* clear the interrupt */ + DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1); +} + +/* Read result from last MPI operation */ +void esp_mpi_read_result_hw_op(mbedtls_mpi *Z, size_t z_words) +{ + wait_op_complete(); + mem_block_to_mpi(Z, RSA_MEM_Z_BLOCK_BASE, z_words); +} + +/* Z = (X * Y) mod M */ +void esp_mpi_mul_mpi_mod_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, const mbedtls_mpi *Rinv, mbedtls_mpi_uint Mprime, size_t hw_words) +{ + /* Load M, X, Rinv, Mprime (Mprime is mod 2^32) */ + mpi_to_mem_block(RSA_MEM_M_BLOCK_BASE, M, hw_words); + mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, hw_words); + mpi_to_mem_block(RSA_MEM_RB_BLOCK_BASE, Rinv, hw_words); + DPORT_REG_WRITE(RSA_M_DASH_REG, (uint32_t)Mprime); + + /* "mode" register loaded with number of 512-bit blocks, minus 1 */ + DPORT_REG_WRITE(RSA_MULT_MODE_REG, (hw_words / 16) - 1); + + /* Execute first stage montgomery multiplication */ + start_op(RSA_MULT_START_REG); + + wait_op_complete(); + + /* execute second stage */ + /* Load Y to X input memory block, rerun */ + mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, Y, hw_words); + + start_op(RSA_MULT_START_REG); +} + +/* Z = X * Y */ +void esp_mpi_mul_mpi_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t hw_words) +{ + /* Copy X (right-extended) & Y (left-extended) to memory block */ + mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, hw_words); + mpi_to_mem_block(RSA_MEM_Z_BLOCK_BASE + hw_words * 4, Y, hw_words); + /* NB: as Y is left-extended, we don't zero the bottom words_mult words of Y block. + This is OK for now because zeroing is done by hardware when we do esp_mpi_acquire_hardware(). + */ + + DPORT_REG_WRITE(RSA_M_DASH_REG, 0); + + /* "mode" register loaded with number of 512-bit blocks in result, + plus 7 (for range 9-12). (this is ((N~ / 32) - 1) + 8)) + */ + DPORT_REG_WRITE(RSA_MULT_MODE_REG, ((hw_words * 2) / 16) + 7); + + start_op(RSA_MULT_START_REG); + +} + + +int esp_mont_hw_op(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, + mbedtls_mpi_uint Mprime, + size_t hw_words, + bool again) +{ + // Note Z may be the same pointer as X or Y + int ret = 0; + + // montgomery mult prepare + if (again == false) { + mpi_to_mem_block(RSA_MEM_M_BLOCK_BASE, M, hw_words); + DPORT_REG_WRITE(RSA_M_DASH_REG, Mprime); + DPORT_REG_WRITE(RSA_MULT_MODE_REG, hw_words / 16 - 1); + } + + mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, hw_words); + mpi_to_mem_block(RSA_MEM_RB_BLOCK_BASE, Y, hw_words); + + start_op(RSA_MULT_START_REG); + Z->s = 1; // The sign of Z will be = M->s (but M->s is always 1) + MBEDTLS_MPI_CHK( mbedtls_mpi_grow(Z, hw_words) ); + + wait_op_complete(); + + /* Read back the result */ + mem_block_to_mpi(Z, RSA_MEM_Z_BLOCK_BASE, hw_words); + + + /* from HAC 14.36 - 3. If Z >= M then Z = Z - M */ + if (mbedtls_mpi_cmp_mpi(Z, M) >= 0) { + MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(Z, Z, M)); + } +cleanup: + return ret; +} + + + +/* Special-case of mbedtls_mpi_mult_mpi(), where we use hardware montgomery mod + multiplication to calculate an mbedtls_mpi_mult_mpi result where either + A or B are >2048 bits so can't use the standard multiplication method. + + Result (z_words, based on A bits + B bits) must still be less than 4096 bits. + + This case is simpler than the general case modulo multiply of + esp_mpi_mul_mpi_mod() because we can control the other arguments: + + * Modulus is chosen with M=(2^num_bits - 1) (ie M=R-1), so output + isn't actually modulo anything. + * Mprime and Rinv are therefore predictable as follows: + Mprime = 1 + Rinv = 1 + + (See RSA Accelerator section in Technical Reference for more about Mprime, Rinv) +*/ +void esp_mpi_mult_mpi_failover_mod_mult_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words) +{ + size_t hw_words = num_words; + + /* M = 2^num_words - 1, so block is entirely FF */ + for (int i = 0; i < hw_words; i++) { + DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + i * 4, UINT32_MAX); + } + /* Mprime = 1 */ + DPORT_REG_WRITE(RSA_M_DASH_REG, 1); + + /* "mode" register loaded with number of 512-bit blocks, minus 1 */ + DPORT_REG_WRITE(RSA_MULT_MODE_REG, (hw_words / 16) - 1); + + /* Load X */ + mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, hw_words); + + /* Rinv = 1, write first word */ + DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE, 1); + + /* Zero out rest of the Rinv words */ + for (int i = 1; i < hw_words; i++) { + DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + i * 4, 0); + } + + start_op(RSA_MULT_START_REG); + + wait_op_complete(); + + /* finish the modular multiplication */ + /* Load Y to X input memory block, rerun */ + mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, Y, hw_words); + + start_op(RSA_MULT_START_REG); + +} +#endif //CONFIG_IDF_TARGET_ESP32 diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32.h b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32.h new file mode 100644 index 000000000..90c3325b5 --- /dev/null +++ b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32.h @@ -0,0 +1,82 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#if CONFIG_IDF_TARGET_ESP32 +#pragma once + +#include_next "mbedtls/bignum.h" +#include "sdkconfig.h" + +/** + * This is a wrapper for the main mbedtls/bignum.h. This wrapper + * provides a few additional ESP32-only functions. + * + * This is because we don't set MBEDTLS_BIGNUM_ALT in the same way we + * do for AES, SHA, etc. Because we still use most of the bignum.h + * implementation and just replace a few hardware accelerated + * functions (see MBEDTLS_MPI_EXP_MOD_ALT & MBEDTLS_MPI_MUL_MPI_ALT in + * esp_config.h). + * + * @note Unlike the other hardware accelerator support functions in esp32/hwcrypto, there is no + * generic "hwcrypto/bignum.h" header for using these functions without mbedTLS. The reason for this + * is that all of the function implementations depend strongly upon the mbedTLS MPI implementation. + */ + +/** + * @brief Lock access to RSA Accelerator (MPI/bignum operations) + * + * RSA Accelerator hardware unit can only be used by one + * consumer at a time. + * + * @note This function is non-recursive (do not call it twice from the + * same task.) + * + * @note You do not need to call this if you are using the mbedTLS bignum.h + * API or esp_mpi_xxx functions. This function is only needed if you + * want to call ROM RSA functions or access the registers directly. + * + */ +void esp_mpi_acquire_hardware(void); + +/** + * @brief Unlock access to RSA Accelerator (MPI/bignum operations) + * + * Has to be called once for each call to esp_mpi_acquire_hardware(). + * + * @note You do not need to call this if you are using the mbedTLS bignum.h + * API or esp_mpi_xxx functions. This function is only needed if you + * want to call ROM RSA functions or access the registers directly. + */ +void esp_mpi_release_hardware(void); + +//#if CONFIG_MBEDTLS_HARDWARE_MPI + +/* @brief MPI modular mupltiplication function + * + * Calculates Z = (X * Y) mod M using MPI hardware acceleration. + * + * This is not part of the standard mbedTLS bignum API. + * + * @note All of X, Y & Z should be less than 4096 bit long or an error is returned. + * + * @param Z Result bignum, should be pre-initialised with mbedtls_mpi_init(). + * @param X First multiplication argument. + * @param Y Second multiplication argument. + * @param M Modulus value for result. + * + * @return 0 on success, mbedTLS MPI error codes on failure. + */ +int esp_mpi_mul_mpi_mod(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M); + +//#endif // CONFIG_MBEDTLS_HARDWARE_MPI +#endif CONFIG_IDF_TARGET_ESP32 diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32_C3.c b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32_C3.c new file mode 100644 index 000000000..a96d514b9 --- /dev/null +++ b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32_C3.c @@ -0,0 +1,108 @@ +/** + * \brief Multi-precision integer library, ESP-IDF hardware accelerated parts + * + * based on mbedTLS implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * Additions Copyright (C) 2016-2020, Espressif Systems (Shanghai) PTE Ltd + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#if CONFIG_IDF_TARGET_ESP32C3 +#if __has_include("esp_idf_version.h") +#include "esp_idf_version.h" +#endif + +#include +#include "soc/hwcrypto_periph.h" +#include "driver/periph_ctrl.h" +#include "mbedtls/bignum.h" +#include "bignum_impl.h" +#include "soc/system_reg.h" +#include "soc/periph_defs.h" +#include "esp_crypto_lock.h" + +/* Copy mbedTLS MPI bignum 'mpi' to hardware memory block at 'mem_base'. + + If hw_words is higher than the number of words in the bignum then + these additional words will be zeroed in the memory buffer. + +*/ +static inline void mpi_to_mem_block(uint32_t mem_base, const mbedtls_mpi *mpi, size_t num_words) +{ + uint32_t *pbase = (uint32_t *)mem_base; + uint32_t copy_words = MIN(num_words, mpi->n); + + /* Copy MPI data to memory block registers */ + for (int i = 0; i < copy_words; i++) { + pbase[i] = mpi->p[i]; + } + + /* Zero any remaining memory block data */ + for (int i = copy_words; i < num_words; i++) { + pbase[i] = 0; + } +} + +/* Read mbedTLS MPI bignum back from hardware memory block. + + Reads num_words words from block. + + Bignum 'x' should already be grown to at least num_words by caller (can be done while + calculation is in progress, to save some cycles) +*/ +static inline void mem_block_to_mpi(mbedtls_mpi *x, uint32_t mem_base, int num_words) +{ + + /* Copy data from memory block registers */ + const size_t REG_WIDTH = sizeof(uint32_t); + for (size_t i = 0; i < num_words; i++) { + x->p[i] = REG_READ(mem_base + (i * REG_WIDTH)); + } + /* Zero any remaining limbs in the bignum, if the buffer is bigger + than num_words */ + for (size_t i = num_words; i < x->n; i++) { + x->p[i] = 0; + } + +} + +/* Begin an RSA operation. op_reg specifies which 'START' register + to write to. +*/ +static inline void start_op(uint32_t op_reg) +{ + /* Clear interrupt status */ + REG_WRITE(RSA_CLEAR_INTERRUPT_REG, 1); + + /* Note: above REG_WRITE includes a memw, so we know any writes + to the memory blocks are also complete. */ + + REG_WRITE(op_reg, 1); +} + +/* Wait for an RSA operation to complete. +*/ +static inline void wait_op_complete(void) +{ + while (REG_READ(RSA_QUERY_INTERRUPT_REG) != 1) + { } + + /* clear the interrupt */ + REG_WRITE(RSA_CLEAR_INTERRUPT_REG, 1); +} + +#endif //CONFIG_IDF_TARGET_ESP32C3 diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32_C3.h b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32_C3.h new file mode 100644 index 000000000..333615c3f --- /dev/null +++ b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32_C3.h @@ -0,0 +1,87 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#if CONFIG_IDF_TARGET_ESP32C3 +#pragma once + +#include_next "mbedtls/bignum.h" +#include "sdkconfig.h" + +/** + * This is a wrapper for the main mbedtls/bignum.h. This wrapper + * provides a few additional ESP32-only functions. + * + * This is because we don't set MBEDTLS_BIGNUM_ALT in the same way we + * do for AES, SHA, etc. Because we still use most of the bignum.h + * implementation and just replace a few hardware accelerated + * functions (see MBEDTLS_MPI_EXP_MOD_ALT & MBEDTLS_MPI_MUL_MPI_ALT in + * esp_config.h). + * + * @note Unlike the other hardware accelerator support functions in esp32/hwcrypto, there is no + * generic "hwcrypto/bignum.h" header for using these functions without mbedTLS. The reason for this + * is that all of the function implementations depend strongly upon the mbedTLS MPI implementation. + */ + +/** + * @brief Lock access to RSA Accelerator (MPI/bignum operations) + * + * RSA Accelerator hardware unit can only be used by one + * consumer at a time. + * + * @note This function is non-recursive (do not call it twice from the + * same task.) + * + * @note You do not need to call this if you are using the mbedTLS bignum.h + * API or esp_mpi_xxx functions. This function is only needed if you + * want to call ROM RSA functions or access the registers directly. + * + */ +void esp_mpi_acquire_hardware(void); + +/** + * @brief Unlock access to RSA Accelerator (MPI/bignum operations) + * + * Has to be called once for each call to esp_mpi_acquire_hardware(). + * + * @note You do not need to call this if you are using the mbedTLS bignum.h + * API or esp_mpi_xxx functions. This function is only needed if you + * want to call ROM RSA functions or access the registers directly. + */ +void esp_mpi_release_hardware(void); + +//#if CONFIG_MBEDTLS_HARDWARE_MPI + +/* @brief MPI modular mupltiplication function + * + * Calculates Z = (X * Y) mod M using MPI hardware acceleration. + * + * This is not part of the standard mbedTLS bignum API. + * + * @note All of X, Y & Z should be less than 4096 bit long or an error is returned. + * + * @param Z Result bignum, should be pre-initialised with mbedtls_mpi_init(). + * @param X First multiplication argument. + * @param Y Second multiplication argument. + * @param M Modulus value for result. + * + * @return 0 on success, mbedTLS MPI error codes on failure. + */ +int esp_mpi_mul_mpi_mod(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M); + +void esp_mpi_mul_mpi_mod_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, const mbedtls_mpi *Rinv, mbedtls_mpi_uint Mprime, size_t num_words); +static inline void mpi_to_mem_block(uint32_t mem_base, const mbedtls_mpi *mpi, size_t num_words); +void esp_mpi_mul_mpi_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words); + + +//#endif // CONFIG_MBEDTLS_HARDWARE_MPI +#endif //CONFIG_IDF_TARGET_ESP32C3 diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_impl.h b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_impl.h index 0c70fa339..20943499b 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_impl.h +++ b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_impl.h @@ -10,7 +10,7 @@ exponentiation instead. */ -#define CONFIG_IDF_TARGET_ESP32 1 +// #define CONFIG_IDF_TARGET_ESP32 1 #if CONFIG_IDF_TARGET_ESP32 #define ESP_MPI_USE_MONT_EXP @@ -19,7 +19,7 @@ //#define MBEDTLS_MPI_MUL_MPI_ALT #endif - +#if CONFIG_IDF_TARGET_ESP32 int esp_mpi_exp_mod( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, mbedtls_mpi *_Rinv ); /** @@ -86,7 +86,11 @@ int esp_mont_hw_op(mbedtls_mpi* Z, const mbedtls_mpi* X, const mbedtls_mpi* Y, c * */ void esp_mpi_exp_mpi_mod_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, const mbedtls_mpi *Rinv, mbedtls_mpi_uint Mprime, size_t hw_words); - +#endif //CONFIG_IDF_TARGET_ESP32 #endif //ESP_MPI_USE_MONT_EXP +#if CONFIG_IDF_TARGET_ESP32C3 +void esp_mpi_exp_mpi_mod_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, const mbedtls_mpi *Rinv, mbedtls_mpi_uint Mprime, size_t num_words); +#endif //CONFIG_IDF_TARGET_ESP32C3 + #endif diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/esp_bignum.c b/lib/libesp32_div/ESP32-HomeKit/src/port/esp_bignum.c index 44e0a798c..8d6936e60 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/port/esp_bignum.c +++ b/lib/libesp32_div/ESP32-HomeKit/src/port/esp_bignum.c @@ -79,7 +79,7 @@ static inline size_t bits_to_words(size_t bits) /* Return the number of words actually used to represent an mpi number. */ -#if defined(MBEDTLS_MPI_EXP_MOD_ALT) +#if defined(MBEDTLS_MPI_EXP_MOD_ALT) || defined(CONFIG_IDF_TARGET_ESP32C3) static size_t mpi_words(const mbedtls_mpi *mpi) { for (size_t i = mpi->n; i > 0; i--) { @@ -369,6 +369,87 @@ cleanup: #endif /* MBEDTLS_MPI_EXP_MOD_ALT */ +#if CONFIG_IDF_TARGET_ESP32C3 +int esp_mpi_exp_mod( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, mbedtls_mpi *_Rinv ) +{ + int ret = 0; + size_t x_words = mpi_words(X); + size_t y_words = mpi_words(Y); + size_t m_words = mpi_words(M); + + + /* "all numbers must be the same length", so choose longest number + as cardinal length of operation... + */ + size_t num_words = esp_mpi_hardware_words(MAX(m_words, MAX(x_words, y_words))); + + mbedtls_mpi Rinv_new; /* used if _Rinv == NULL */ + mbedtls_mpi *Rinv; /* points to _Rinv (if not NULL) othwerwise &RR_new */ + mbedtls_mpi_uint Mprime; + + if (mbedtls_mpi_cmp_int(M, 0) <= 0 || (M->p[0] & 1) == 0) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + if (mbedtls_mpi_cmp_int(Y, 0) < 0) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + if (mbedtls_mpi_cmp_int(Y, 0) == 0) { + return mbedtls_mpi_lset(Z, 1); + } + + if (num_words * 32 > SOC_RSA_MAX_BIT_LEN) { + return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + } + + /* Determine RR pointer, either _RR for cached value + or local RR_new */ + if (_Rinv == NULL) { + mbedtls_mpi_init(&Rinv_new); + Rinv = &Rinv_new; + } else { + Rinv = _Rinv; + } + if (Rinv->p == NULL) { + MBEDTLS_MPI_CHK(calculate_rinv(Rinv, M, num_words)); + } + + Mprime = modular_inverse(M); + + // Montgomery exponentiation: Z = X ^ Y mod M (HAC 14.94) +#ifdef ESP_MPI_USE_MONT_EXP + ret = mpi_montgomery_exp_calc(Z, X, Y, M, Rinv, num_words, Mprime) ; + MBEDTLS_MPI_CHK(ret); +#else + esp_mpi_enable_hardware_hw_op(); + + esp_mpi_exp_mpi_mod_hw_op(X, Y, M, Rinv, Mprime, num_words); + ret = mbedtls_mpi_grow(Z, m_words); + if (ret != 0) { + esp_mpi_disable_hardware_hw_op(); + goto cleanup; + } + esp_mpi_read_result_hw_op(Z, m_words); + esp_mpi_disable_hardware_hw_op(); +#endif + + // Compensate for negative X + if (X->s == -1 && (Y->p[0] & 1) != 0) { + Z->s = -1; + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(Z, M, Z)); + } else { + Z->s = 1; + } + +cleanup: + if (_Rinv == NULL) { + mbedtls_mpi_free(&Rinv_new); + } + return ret; +} +#endif //CONFIG_IDF_TARGET_ESP32C3 + #if defined(MBEDTLS_MPI_MUL_MPI_ALT) /* MBEDTLS_MPI_MUL_MPI_ALT */