#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#if defined(WOLFSSL_ESPIDF)
#include "sdkconfig.h"
#include <wolfssl/wolfcrypt/port/Espressif/esp32-crypt.h>
#include <wolfssl/wolfcrypt/logging.h>
#if !defined(NO_RSA) || defined(HAVE_ECC)
#if defined(WOLFSSL_ESP32_CRYPT_RSA_PRI) && \
!defined(NO_WOLFSSL_ESP32_CRYPT_RSA_PRI)
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
#include <wolfssl/wolfcrypt/wolfmath.h>
#ifndef SINGLE_THREADED
#include <freertos/semphr.h>
#endif
#define ESP_HW_RSAMIN_BIT 512
#define ESP_HW_RSAMAX_BIT 4096
#if defined(CONFIG_IDF_TARGET_ESP32)
#define ESP_HW_MOD_RSAMAX_BITS 4096
#define ESP_HW_MULTI_RSAMAX_BITS 2048
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
#define ESP_HW_MOD_RSAMAX_BITS 4096
#define ESP_HW_MULTI_RSAMAX_BITS 2048
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
#define ESP_HW_MOD_RSAMAX_BITS 4096
#define ESP_HW_MULTI_RSAMAX_BITS 2048
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
#define ESP_HW_MOD_RSAMAX_BITS 3072
#define ESP_HW_MULTI_RSAMAX_BITS 1536
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
#define ESP_HW_MOD_RSAMAX_BITS 3072
#define ESP_HW_MULTI_RSAMAX_BITS 1536
#else
#define ESP_HW_MOD_RSAMAX_BITS 0
#define ESP_HW_MULTI_RSAMAX_BITS 0
#endif
#define BYTE_TO_WORDS(s) (((s+3)>>2))
#define BITS_TO_WORDS(s) (((s+31)>>3)>>2)
#define BITS_IN_ONE_WORD 32
#ifndef ESP_RSA_MULM_BITS
#define ESP_RSA_MULM_BITS 16
#endif
#ifndef ESP_RSA_EXPT_XBITS
#define ESP_RSA_EXPT_XBITS 8
#endif
#ifndef ESP_RSA_EXPT_YBITS
#define ESP_RSA_EXPT_YBITS 8
#endif
#ifndef ESP_RSA_TIMEOUT_CNT
#define ESP_RSA_TIMEOUT_CNT 0x5000000
#endif
#define ESP_TIMEOUT(cnt) (cnt >= ESP_RSA_TIMEOUT_CNT)
#ifndef ESP_RSA_WAIT_TIMEOUT_CNT
#define ESP_RSA_WAIT_TIMEOUT_CNT 0x20
#endif
#define ESP_WAIT_TIMEOUT(cnt) (cnt >= ESP_RSA_WAIT_TIMEOUT_CNT)
#if defined(CONFIG_IDF_TARGET_ESP32C3)
#include <soc/system_reg.h>
#include <soc/hwcrypto_reg.h>
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
#include <soc/pcr_reg.h>
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
#include <soc/system_reg.h>
#include <soc/hwcrypto_reg.h>
#endif
static const char* const TAG = "wolfssl_esp32_mp";
#ifdef DEBUG_WOLFSSL
static int hw_validation = 0;
#define SET_HW_VALIDATION {hw_validation = 1;}
#define CLR_HW_VALIDATION {hw_validation = 0;}
#define IS_HW_VALIDATION (hw_validation == 1)
#undef WOLFSSL_HW_METRICS
#define WOLFSSL_HW_METRICS
#endif
struct esp_mp_helper
{
MATH_INT_T r_inv;
word32 exp;
word32 Xs;
word32 Ys;
word32 Ms;
word32 Rs;
word32 maxWords_sz;
word32 hwWords_sz;
mp_digit mp;
#ifdef DEBUG_WOLFSSL
mp_digit mp2;
#endif
};
static portMUX_TYPE wc_rsa_reg_lock = portMUX_INITIALIZER_UNLOCKED;
#ifdef WOLFSSL_HW_METRICS
static unsigned long esp_mp_max_used = 0;
static unsigned long esp_mp_max_timeout = 0;
static unsigned long esp_mp_max_wait_timeout;
#ifndef NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL
static unsigned long esp_mp_mul_usage_ct = 0;
static unsigned long esp_mp_mul_error_ct = 0;
static unsigned long esp_mp_mul_tiny_ct = 0;
static unsigned long esp_mp_mul_max_exceeded_ct = 0;
#endif
#ifndef NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD
static unsigned long esp_mp_mulmod_small_x_ct = 0;
static unsigned long esp_mp_mulmod_small_y_ct = 0;
static unsigned long esp_mp_mulmod_max_exceeded_ct = 0;
static unsigned long esp_mp_mulmod_usage_ct = 0;
static unsigned long esp_mp_mulmod_fallback_ct = 0;
static unsigned long esp_mp_mulmod_even_mod_ct = 0;
static unsigned long esp_mp_mulmod_error_ct = 0;
#endif
#ifndef NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD
static unsigned long esp_mp_exptmod_usage_ct = 0;
static unsigned long esp_mp_exptmod_error_ct = 0;
static unsigned long esp_mp_exptmod_max_exceeded_ct = 0;
static unsigned long esp_mp_exptmod_fallback_ct = 0;
#endif
#endif
#ifdef SINGLE_THREADED
static int single_thread_locked = 0;
#else
static wolfSSL_Mutex mp_mutex;
static int espmp_CryptHwMutexInit = 0;
#endif
#ifdef DEBUG_WOLFSSL
#ifndef NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD
static int esp_mp_exptmod_depth_counter = 0;
#endif
#endif
static int esp_mp_hw_wait_clean(void)
{
int ret = MP_OKAY;
word32 timeout = 0;
#if defined(CONFIG_IDF_TARGET_ESP32)
ESP_EM__PRE_MP_HW_WAIT_CLEAN
while(!ESP_TIMEOUT(++timeout) && DPORT_REG_READ(RSA_CLEAN_REG) == 0) {
ESP_EM__MP_HW_WAIT_CLEAN
}
#elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6)
ESP_EM__PRE_MP_HW_WAIT_CLEAN
while (!ESP_TIMEOUT(++timeout) &&
DPORT_REG_READ(RSA_QUERY_CLEAN_REG) != 1) {
ESP_EM__MP_HW_WAIT_CLEAN
}
#elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
ESP_EM__PRE_MP_HW_WAIT_CLEAN
while (!ESP_TIMEOUT(++timeout) &&
DPORT_REG_READ(RSA_QUERY_CLEAN_REG) != 1) {
ESP_EM__MP_HW_WAIT_CLEAN
}
#else
#endif
#if defined(WOLFSSL_HW_METRICS)
if (timeout > esp_mp_max_wait_timeout) {
esp_mp_max_wait_timeout = timeout;
}
if (timeout > esp_mp_max_timeout) {
esp_mp_max_timeout = timeout;
}
#endif
if (ESP_TIMEOUT(timeout)) {
#ifndef SINGLE_THREADED
ESP_LOGI(TAG, "Consider #define SINGLE_THREADED. See docs");
#endif
ESP_LOGE(TAG, "esp_mp_hw_wait_clean waiting HW ready timed out.");
ret = WC_HW_WAIT_E;
}
return ret;
}
static int esp_mp_hw_islocked(void)
{
int ret = FALSE;
#ifdef SINGLE_THREADED
if (single_thread_locked == FALSE) {
ESP_LOGV(TAG, "SINGLE_THREADED esp_mp_hw_islocked = false");
}
else {
ESP_LOGV(TAG, "SINGLE_THREADED esp_mp_hw_islocked = true");
ret = TRUE;
}
#else
TaskHandle_t mutexHolder = xSemaphoreGetMutexHolder(mp_mutex);
if (mutexHolder == NULL) {
ESP_LOGV(TAG, "multi-threaded esp_mp_hw_islocked = false");
}
else {
ESP_LOGV(TAG, "multi-threaded esp_mp_hw_islocked = true");
ret = TRUE;
}
#endif
return ret;
}
static int esp_mp_hw_lock(void)
{
int ret = ESP_OK;
ESP_LOGV(TAG, "enter esp_mp_hw_lock");
#ifdef SINGLE_THREADED
single_thread_locked = TRUE;
#else
if (espmp_CryptHwMutexInit == ESP_OK) {
ret = esp_CryptHwMutexInit(&mp_mutex);
if (ret == ESP_OK) {
espmp_CryptHwMutexInit = TRUE;
}
else {
ESP_LOGE(TAG, "mp mutex initialization failed.");
}
}
else {
}
if (ret == ESP_OK) {
ret = esp_CryptHwMutexLock(&mp_mutex, ESP_MP_HW_LOCK_MAX_DELAY);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "mp engine lock failed.");
ret = WC_HW_WAIT_E;
}
}
#endif
#if defined(CONFIG_IDF_TARGET_ESP32)
if (ret == ESP_OK) {
periph_module_enable(PERIPH_RSA_MODULE);
portENTER_CRITICAL_SAFE(&wc_rsa_reg_lock);
{
DPORT_REG_CLR_BIT(DPORT_RSA_PD_CTRL_REG, DPORT_RSA_PD);
ESP_EM__POST_SP_MP_HW_LOCK
}
portEXIT_CRITICAL_SAFE(&wc_rsa_reg_lock);
}
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
if (ret == ESP_OK) {
periph_module_enable(PERIPH_RSA_MODULE);
portENTER_CRITICAL_SAFE(&wc_rsa_reg_lock);
{
DPORT_REG_SET_BIT((volatile void *)(SYSTEM_PERIP_CLK_EN1_REG),
SYSTEM_CRYPTO_RSA_CLK_EN );
DPORT_REG_CLR_BIT((volatile void *)(SYSTEM_RSA_PD_CTRL_REG),
SYSTEM_RSA_MEM_PD );
}
portEXIT_CRITICAL_SAFE(&wc_rsa_reg_lock);
}
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
if (ret == ESP_OK) {
periph_module_enable(PERIPH_RSA_MODULE);
portENTER_CRITICAL_SAFE(&wc_rsa_reg_lock);
{
DPORT_REG_CLR_BIT((volatile void *)(PCR_DS_CONF_REG),
PCR_DS_RST_EN );
DPORT_REG_SET_BIT((volatile void *)(PCR_RSA_CONF_REG),
PCR_RSA_CLK_EN );
DPORT_REG_CLR_BIT((volatile void *)(PCR_RSA_CONF_REG),
PCR_RSA_RST_EN );
}
portEXIT_CRITICAL_SAFE(&wc_rsa_reg_lock);
}
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
if (ret == ESP_OK) {
periph_module_enable(PERIPH_RSA_MODULE);
portENTER_CRITICAL_SAFE(&wc_rsa_reg_lock);
{
DPORT_REG_SET_BIT((volatile void *)(DPORT_CPU_PERIP_CLK_EN1_REG),
DPORT_CRYPTO_RSA_CLK_EN );
DPORT_REG_CLR_BIT((volatile void *)(DPORT_RSA_PD_CTRL_REG),
DPORT_RSA_MEM_PD );
}
portEXIT_CRITICAL_SAFE(&wc_rsa_reg_lock);
}
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
if (ret == ESP_OK) {
periph_module_enable(PERIPH_RSA_MODULE);
portENTER_CRITICAL_SAFE(&wc_rsa_reg_lock);
{
DPORT_REG_CLR_BIT(SYSTEM_RSA_PD_CTRL_REG, SYSTEM_RSA_MEM_PD);
}
portEXIT_CRITICAL_SAFE(&wc_rsa_reg_lock);
}
#else
#endif
ESP_LOGV(TAG, "leave esp_mp_hw_lock");
return ret;
}
static int esp_mp_hw_unlock(void)
{
int ret = MP_OKAY;
if (esp_mp_hw_islocked()) {
#if defined(CONFIG_IDF_TARGET_ESP32)
DPORT_REG_SET_BIT(DPORT_RSA_PD_CTRL_REG, DPORT_RSA_PD);
periph_module_disable(PERIPH_RSA_MODULE);
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
portENTER_CRITICAL_SAFE(&wc_rsa_reg_lock);
{
DPORT_REG_CLR_BIT(
(volatile void *)(DR_REG_RSA_BASE + SYSTEM_CRYPTO_RSA_CLK_EN),
SYSTEM_PERIP_CLK_EN1_REG);
DPORT_REG_SET_BIT(
(volatile void *)(DR_REG_RSA_BASE + SYSTEM_RSA_MEM_PD),
SYSTEM_RSA_PD_CTRL_REG);
}
portEXIT_CRITICAL_SAFE(&wc_rsa_reg_lock);
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
portENTER_CRITICAL_SAFE(&wc_rsa_reg_lock);
{
DPORT_REG_SET_BIT((volatile void *)(PCR_RSA_CONF_REG),
PCR_RSA_RST_EN);
DPORT_REG_CLR_BIT((volatile void *)(PCR_RSA_CONF_REG),
PCR_RSA_CLK_EN);
}
portEXIT_CRITICAL_SAFE(&wc_rsa_reg_lock);
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
DPORT_REG_SET_BIT(DPORT_RSA_PD_CTRL_REG, DPORT_RSA_MEM_PD);
periph_module_disable(PERIPH_RSA_MODULE);
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
DPORT_REG_SET_BIT(SYSTEM_RSA_PD_CTRL_REG, SYSTEM_RSA_MEM_PD);
periph_module_disable(PERIPH_RSA_MODULE);
#else
ESP_LOGW(TAG, "Warning: esp_mp_hw_unlock called for unknown target");
#endif
#if defined(SINGLE_THREADED)
single_thread_locked = FALSE;
#else
esp_CryptHwMutexUnLock(&mp_mutex);
#endif
ESP_LOGV(TAG, "exit esp_mp_hw_unlock");
}
else {
#ifdef WOLFSSL_ESP32_HW_LOCK_DEBUG
ESP_LOGW(TAG, "Warning: esp_mp_hw_unlock called when not locked.");
#endif
}
return ret;
}
#if !defined(NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD) \
|| \
!defined(NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD)
static int esp_calc_Mdash(MATH_INT_T *M, word32 k, mp_digit* md)
{
int ret = MP_OKAY;
ESP_LOGV(TAG, "\nBegin esp_calc_Mdash \n");
#ifdef USE_ALT_MPRIME
MATH_INT_T X[1] = { };
MATH_INT_T P[1] = { };
MATH_INT_T Y[1] = { };
word32 Xs;
ESP_LOGV(TAG, "\nBegin esp_calc_Mdash USE_ALT_MPRIME\n");
mp_init(X);
mp_init(P);
mp_init(Y);
X->dp[0] = 1;
X->sign = MP_NEG;
X->used = 1;
Xs = mp_count_bits(X);
P->dp[1] = 1;
P->used = 2;
ret = mp_exptmod(M, X, P, Y);
*md = Y->dp[0];
ESP_LOGI(TAG, "esp_calc_Mdash %u", *md);
#else
int i;
int xi;
int b0 = 1;
int bi;
word32 N = 0;
word32 x;
ESP_LOGV(TAG, "\nBegin esp_calc_Mdash\n");
N = M->dp[0];
bi = b0;
x = 0;
for (i = 0; i < k; i++) {
xi = bi % 2;
if (xi < 0) {
xi *= -1;
}
bi = (bi - N * xi) / 2;
x |= (xi << i);
}
*md = ~x + 1;
#endif
ESP_LOGV(TAG, "\nEnd esp_calc_Mdash \n");
return ret;
}
#endif
static int esp_clean_result(MATH_INT_T* Z, int used_padding)
{
int ret = MP_OKAY;
uint16_t this_extra;
uint16_t dp_length = 0; (void) dp_length;
#ifdef USE_FAST_MATH
#undef MP_SIZE
#define MP_SIZE FP_SIZE
dp_length = FP_SIZE;
#else
#undef MP_SIZE
#define MP_SIZE 128
dp_length = SP_INT_DIGITS;
#endif
this_extra = Z->used;
if (this_extra > MP_SIZE) {
ESP_LOGW(TAG, "Warning (Z->used: %d) > (MP_SIZE: %d); adjusting...",
Z->used, MP_SIZE);
this_extra = MP_SIZE;
}
while (Z->dp[this_extra] > 0 && (this_extra < MP_SIZE)) {
ESP_LOGV(TAG, "Adjust! %d", this_extra);
Z->dp[this_extra] = 0;
this_extra++;
}
if (Z->used > 0) {
ESP_LOGV(TAG, "ZTrim: Z->used = %d", Z->used);
for (size_t i = Z->used; i > 0; i--) {
if (Z->dp[i - 1] == 0) {
Z->used = i - 1;
}
else {
break;
}
}
ESP_LOGV(TAG, "New Z->used = %d", Z->used);
}
else {
ESP_LOGV(TAG, "no z-trim needed");
}
#if defined(WOLFSSL_SP_INT_NEGATIVE) || defined(USE_FAST_MATH)
if (Z->sign != 0) {
mp_setneg(Z);
}
#endif
if ((Z->dp[0] == 1) && (Z->used == 1)) {
ESP_LOGV(TAG, "Z->dp[0] == 1");
}
return ret;
}
static int process_start(u_int32_t reg)
{
int ret = MP_OKAY;
DPORT_REG_WRITE((volatile word32*)reg, 1);
ESP_EM__POST_PROCESS_START;
return ret;
}
static int wait_until_done(word32 reg)
{
int ret = MP_OKAY;
word32 timeout = 0;
ESP_EM__MP_HW_WAIT_DONE;
while (!ESP_TIMEOUT(++timeout) && DPORT_REG_READ(reg) != 1) {
asm volatile("nop");
}
ESP_EM__DPORT_FIFO_READ;
#if defined(CONFIG_IDF_TARGET_ESP32C6)
DPORT_REG_WRITE(RSA_INT_CLR_REG, 1);
DPORT_REG_WRITE(RSA_INT_ENA_REG, 0);
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
#else
DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
#endif
#if defined(WOLFSSL_HW_METRICS)
if (timeout > esp_mp_max_timeout) {
esp_mp_max_timeout = timeout;
}
#endif
if (ESP_TIMEOUT(timeout)) {
ESP_LOGE(TAG, "rsa operation timed out.");
ret = WC_HW_E;
}
return ret;
}
static int esp_memblock_to_mpint(const word32 mem_address,
MATH_INT_T* mp,
word32 numwords)
{
int ret = MP_OKAY;
#ifdef USE_ESP_DPORT_ACCESS_READ_BUFFER
esp_dport_access_read_buffer((word32*)mp->dp, mem_address, numwords);
#else
ESP_EM__PRE_DPORT_READ;
DPORT_INTERRUPT_DISABLE();
ESP_EM__READ_NON_FIFO_REG;
for (volatile word32 i = 0; i < numwords; ++i) {
ESP_EM__3_16;
mp->dp[i] = DPORT_SEQUENCE_REG_READ(
(volatile word32)(mem_address + i * 4));
}
DPORT_INTERRUPT_RESTORE();
#endif
mp->used = numwords;
#if defined(ESP_VERIFY_MEMBLOCK)
ret = XMEMCMP((const word32 *)mem_address,
(const word32 *)&mp->dp,
numwords * sizeof(word32));
if (ret != ESP_OK) {
ESP_LOGW(TAG, "Validation Failure esp_memblock_to_mpint.\n"
"Reading %u Words at Address = 0x%08x",
(int)(numwords * sizeof(word32)),
(unsigned int)mem_address);
ESP_LOGI(TAG, "Trying again... ");
esp_dport_access_read_buffer((word32*)mp->dp, mem_address, numwords);
mp->used = numwords;
if (0 != XMEMCMP((const void *)mem_address,
(const void *)&mp->dp,
numwords * sizeof(word32))) {
ESP_LOGE(TAG, "Validation Failure esp_memblock_to_mpint "
"a second time. Giving up.");
ret = MP_VAL;
}
else {
ESP_LOGI(TAG, "Successfully re-read after Validation Failure.");
ret = MP_VAL;
}
}
#endif
return ret;
}
#ifndef NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL
#if defined(CONFIG_IDF_TARGET_ESP32)
static int esp_zero_memblock(u_int32_t mem_address, int wordSz)
{
int ret = MP_OKAY;
ESP_EM__PRE_DPORT_WRITE;
DPORT_INTERRUPT_DISABLE();
for (int i=0; i < wordSz; i++) {
DPORT_REG_WRITE(
(volatile u_int32_t *)(mem_address + (i * sizeof(word32))),
(u_int32_t)(0)
);
}
DPORT_INTERRUPT_RESTORE();
return ret;
}
#endif
#endif
static int esp_mpint_to_memblock(u_int32_t mem_address,
const MATH_INT_T* mp,
const word32 bits,
const word32 hwords)
{
int ret = MP_OKAY;
word32 i;
word32 len;
len = (bits / 8 + ((bits & 7) != 0 ? 1 : 0));
len = (len + sizeof(word32)-1) / sizeof(word32);
ESP_EM__PRE_DPORT_WRITE;
DPORT_INTERRUPT_DISABLE();
for (i=0; i < hwords; i++) {
if (i < len) {
ESP_LOGV(TAG, "Write i = %d value.", i);
DPORT_REG_WRITE(
(volatile u_int32_t*)(mem_address + (i * sizeof(word32))),
mp->dp[i]
);
}
else {
if (i == 0) {
ESP_LOGV(TAG, "esp_mpint_to_memblock zero?");
}
ESP_LOGV(TAG, "Write i = %d value = zero.", i);
DPORT_REG_WRITE(
(volatile u_int32_t*)(mem_address + (i * sizeof(word32))),
(u_int32_t)0
);
}
}
DPORT_INTERRUPT_RESTORE();
#if defined(ESP_VERIFY_MEMBLOCK)
len = XMEMCMP((const void *)mem_address,
(const void *)&mp->dp,
hwords * sizeof(word32)
);
if (len != 0) {
ESP_LOGE(TAG, "esp_mpint_to_memblock compare fails at %d", len);
#ifdef DEBUG_WOLFSSL
esp_show_mp("mp", (MATH_INT_T*)mp);
#endif
ret = MP_VAL;
}
#endif
return ret;
}
static word32 words2hwords(word32 wd)
{
const word32 bit_shift = 4;
return (((wd + 0xf) >> bit_shift) << bit_shift);
}
static word32 bits2words(word32 bits)
{
const word32 d = sizeof(word32) * WOLFSSL_BIT_SIZE;
return ((bits + (d - 1)) / d);
}
#if !defined(NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD) \
|| \
!defined(NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD)
static int esp_get_rinv(MATH_INT_T *rinv, MATH_INT_T *M, word32 exp)
{
#ifdef DEBUG_WOLFSSL
MATH_INT_T rinv2[1];
MATH_INT_T M2[1];
int reti = MP_OKAY;
#endif
int ret = MP_OKAY;
ESP_LOGV(TAG, "\nBegin esp_get_rinv \n");
#ifdef DEBUG_WOLFSSL
mp_copy(M, M2);
mp_copy(rinv, rinv2);
#endif
ret = mp_2expt(rinv, exp);
if (ret == MP_OKAY) {
ret = mp_mod(rinv, M, rinv);
}
else {
ESP_LOGE(TAG, "failed to calculate mp_2expt()");
}
if (ret == MP_OKAY) {
ESP_LOGV(TAG, "esp_get_rinv compute success");
}
else {
ESP_LOGE(TAG, "failed to calculate mp_mod()");
}
#ifdef DEBUG_WOLFSSL
if (ret == MP_OKAY) {
reti = mp_montgomery_calc_normalization(rinv2, M2);
if (reti == MP_OKAY) {
ESP_LOGV(TAG, "mp_montgomery_calc_normalization = %d", reti);
}
else {
ESP_LOGW(TAG, "Error Montgomery calc M2 result = %d", reti);
}
}
#endif
ESP_LOGV(TAG, "\nEnd esp_get_rinv \n");
return ret;
}
#endif
int esp_hw_validation_active(void)
{
#ifdef DEBUG_WOLFSSL
return IS_HW_VALIDATION;
#else
return 0;
#endif
}
int esp_show_mph(struct esp_mp_helper* mph)
{
int ret = MP_OKAY;
if (mph == NULL) {
ESP_LOGE(TAG, "ERROR: Bad esp_mp_helper for esp_show_mph");
return MP_VAL;
}
if (mph->Xs != 0)
ESP_LOGI(TAG, "Xs %d", mph->Xs);
if (mph->Ys != 0)
ESP_LOGI(TAG, "Ys %d", mph->Ys);
if (mph->Ms != 0)
ESP_LOGI(TAG, "Ms %d", mph->Ms);
if (mph->Rs != 0)
ESP_LOGI(TAG, "Rs %d", mph->Rs);
if (mph->maxWords_sz != 0)
ESP_LOGI(TAG, "maxWords_sz %d", mph->maxWords_sz);
if (mph->hwWords_sz != 0)
ESP_LOGI(TAG, "hwWords_sz %d", mph->hwWords_sz);
if (mph->mp != 0)
ESP_LOGI(TAG, "mp %d", mph->mp);
#ifdef DEBUG_WOLFSSL
if (mph->mp2 != 0)
ESP_LOGI(TAG, "mp2 %d", mph->mp2);
#endif
if (mph->r_inv.used != 0)
esp_show_mp("r_inv", &(mph->r_inv));
return ret;
}
#if !defined(NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD) \
|| \
!defined(NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD)
int esp_mp_montgomery_init(MATH_INT_T* X, MATH_INT_T* Y, MATH_INT_T* M,
struct esp_mp_helper* mph)
{
int ret = MP_OKAY;
int exp;
if (mph == NULL) {
ESP_LOGE(TAG, "ERROR: Bad esp_mp_helper, falling back to SW");
return MP_HW_FALLBACK;
}
if ((X == NULL) || (Y == NULL) || (M == NULL) ) {
ESP_LOGE(TAG, "ERROR: Bad Montgomery operand, falling back to SW");
return MP_HW_FALLBACK;
}
XMEMSET(mph, 0, sizeof(struct esp_mp_helper));
mph->Xs = mp_count_bits(X);
#if (ESP_PROHIBIT_SMALL_X == TRUE)
if ((X->used == 1) && (X->dp[1] < (1 << 8))) {
#ifdef WOLFSSL_HW_METRICS
esp_mp_mulmod_small_x_ct++;
#endif
ESP_LOGW(TAG, "esp_mp_montgomery_init MP_HW_FALLBACK Xs = %d",
mph->Xs);
ret = MP_HW_FALLBACK;
}
#endif
if (ret == MP_OKAY) {
mph->Ys = mp_count_bits(Y);
if (mph->Xs <= ESP_RSA_EXPT_XBITS) {
#ifdef WOLFSSL_HW_METRICS
{
esp_mp_mulmod_small_x_ct++;
}
#endif
ESP_LOGV(TAG,
"esp_mp_montgomery_init MP_HW_FALLBACK Xs = %d",
mph->Xs);
ret = MP_HW_FALLBACK;
}
else {
if (mph->Ys <= ESP_RSA_EXPT_YBITS) {
#ifdef WOLFSSL_HW_METRICS
{
esp_mp_mulmod_small_y_ct++;
}
#endif
ESP_LOGV(TAG,
"esp_mp_montgomery_init MP_HW_FALLBACK Ys = %d",
mph->Ys);
ret = MP_HW_FALLBACK;
}
else {
mph->Ms = mp_count_bits(M);
mph->maxWords_sz = bits2words(max(mph->Xs,
max(mph->Ys, mph->Ms)));
mph->hwWords_sz = words2hwords(mph->maxWords_sz);
if ((mph->hwWords_sz << 5) > ESP_HW_RSAMAX_BIT) {
#if defined(WOLFSSL_DEBUG_ESP_HW_MOD_RSAMAX_BITS) || \
defined(WOLFSSL_DEBUG_ESP_HW_MULTI_RSAMAX_BITS)
ESP_LOGW(TAG, "Warning: hwWords_sz = %d (%d bits)"
" exceeds HW maximum bits (%d), "
" falling back to SW.",
mph->hwWords_sz,
mph->hwWords_sz << 5,
ESP_HW_RSAMAX_BIT);
#endif
ret = MP_HW_FALLBACK;
}
}
}
}
ESP_LOGV(TAG, "hwWords_sz = %d", mph->hwWords_sz);
#if defined(CONFIG_IDF_TARGET_ESP32)
exp = mph->hwWords_sz << 6;
#elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6)
exp = mph->maxWords_sz * BITS_IN_ONE_WORD * 2;
#elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
exp = mph->maxWords_sz * BITS_IN_ONE_WORD * 2;
#else
exp = 0;
#endif
if (ret == MP_OKAY && (M != NULL)) {
ret = mp_init((mp_int*)&(mph->r_inv));
if (ret == MP_OKAY) {
ret = esp_get_rinv( (mp_int*)&(mph->r_inv), M, exp);
if (ret == MP_OKAY) {
mph->Rs = mp_count_bits((mp_int*)&(mph->r_inv));
}
else {
ESP_LOGE(TAG, "calculate r_inv failed.");
ret = MP_VAL;
}
}
else {
ESP_LOGE(TAG, "calculate r_inv failed mp_init.");
ret = MP_MEM;
}
}
if (ret == MP_OKAY) {
#ifdef DEBUG_WOLFSSL
ret = mp_montgomery_setup(M, &(mph->mp2) );
#endif
ret = esp_calc_Mdash(M, 32, &(mph->mp));
if (ret != MP_OKAY) {
ESP_LOGE(TAG, "failed esp_calc_Mdash()");
}
}
#ifdef DEBUG_WOLFSSL
if (ret == MP_OKAY) {
if (mph->mp == mph->mp2) {
ESP_LOGV(TAG, "M' match esp_calc_Mdash vs mp_montgomery_setup "
"= %ul !", mph->mp);
}
else {
ESP_LOGW(TAG,
"\n\n"
"M' MISMATCH esp_calc_Mdash = 0x%08x = %d \n"
"vs mp_montgomery_setup = 0x%08x = %d \n\n",
mph->mp,
mph->mp,
mph->mp2,
mph->mp2);
mph->mp = mph->mp2;
}
}
else {
#if 0 #endif
if (ret == MP_HW_FALLBACK) {
ESP_LOGV(TAG, "esp_mp_montgomery_init exit falling back.");
}
else {
ESP_LOGE(TAG, "esp_mp_montgomery_init failed: return code = %d",
ret);
}
}
#endif
return ret;
}
#endif
#ifndef NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL
int esp_mp_mul(MATH_INT_T* X, MATH_INT_T* Y, MATH_INT_T* Z)
{
#ifdef DEBUG_WOLFSSL
MATH_INT_T X2[1];
MATH_INT_T Y2[1];
MATH_INT_T Z2[1];
MATH_INT_T PEEK[1];
#endif
int ret = MP_OKAY;
int mp_mul_lock_called = FALSE;
word32 Xs;
word32 Ys;
word32 Zs;
word32 maxWords_sz = 0;
word32 hwWords_sz = 0;
word32 resultWords_sz = 0;
#if defined(CONFIG_IDF_TARGET_ESP32)
word32 left_pad_offset = 0;
#endif
#if defined(WOLFSSL_SP_INT_NEGATIVE) || defined(USE_FAST_MATH)
int res_sign;
res_sign = (mp_isneg(X) == mp_isneg(Y)) ? MP_ZPOS : MP_NEG;
if (res_sign) {
ESP_LOGV(TAG, "mp_isneg(X) = %d; mp_isneg(Y) = %d; neg = %d ",
mp_isneg(X), mp_isneg(Y), res_sign);
}
#endif
#ifdef WOLFSSL_HW_METRICS
esp_mp_max_used = (X->used > esp_mp_max_used) ? X->used : esp_mp_max_used;
esp_mp_max_used = (Y->used > esp_mp_max_used) ? Y->used : esp_mp_max_used;
#endif
if (mp_iszero(Y) || mp_iszero(X)) {
mp_forcezero(Z);
return MP_OKAY;
}
#ifdef DEBUG_WOLFSSL
if (esp_hw_validation_active()) {
return MP_HW_VALIDATION_ACTIVE;
}
if (X == Z) {
ESP_LOGV(TAG, "mp_mul X == Z");
}
if (Y == Z) {
ESP_LOGV(TAG, "mp_mul Y == Z");
}
mp_init(X2);
mp_init(Y2);
mp_init(Z2);
mp_copy(X, X2);
mp_copy(Y, Y2);
mp_copy(Z, Z2);
if (IS_HW_VALIDATION) {
ESP_LOGE(TAG, "Caller must not try HW when validation active.");
}
else {
SET_HW_VALIDATION;
mp_mul(X2, Y2, Z2);
CLR_HW_VALIDATION;
}
#endif
Xs = mp_count_bits(X);
Ys = mp_count_bits(Y);
Zs = Xs + Ys;
if (Xs > ESP_HW_MULTI_RSAMAX_BITS) {
#if defined(WOLFSSL_DEBUG_ESP_HW_MOD_RSAMAX_BITS)
ESP_LOGW(TAG, "mp-mul X %d bits exceeds max bit length (%d)",
Xs, ESP_HW_MULTI_RSAMAX_BITS);
#endif
esp_mp_mul_max_exceeded_ct++;
return MP_HW_FALLBACK;
}
if (Ys > ESP_HW_MULTI_RSAMAX_BITS) {
#if defined(WOLFSSL_DEBUG_ESP_HW_MOD_RSAMAX_BITS)
ESP_LOGW(TAG, "mp-mul Y %d bits exceeds max bit length (%d)",
Ys, ESP_HW_MULTI_RSAMAX_BITS);
#endif
esp_mp_mul_max_exceeded_ct++;
return MP_HW_FALLBACK;
}
if (Zs <= sizeof(mp_digit) * 8) {
Z->dp[0] = X->dp[0] * Y->dp[0];
Z->used = 1;
#if defined(WOLFSSL_SP_INT_NEGATIVE) || defined(USE_FAST_MATH)
Z->sign = res_sign;
#endif
#if defined(WOLFSSL_HW_METRICS)
esp_mp_mul_tiny_ct++;
#endif
return MP_OKAY;
}
if (ret == MP_OKAY) {
maxWords_sz = bits2words(max(Xs, Ys));
hwWords_sz = words2hwords(maxWords_sz);
resultWords_sz = bits2words(Xs + Ys);
if ( (hwWords_sz << 5) > ESP_HW_MULTI_RSAMAX_BITS) {
#if defined(WOLFSSL_DEBUG_ESP_HW_MOD_RSAMAX_BITS)
ESP_LOGW(TAG, "mp-mul exceeds max bit length (%d)",
ESP_HW_MULTI_RSAMAX_BITS);
#endif
#if defined(WOLFSSL_HW_METRICS)
esp_mp_mul_max_exceeded_ct++;
#endif
return MP_HW_FALLBACK;
}
}
#if defined(CONFIG_IDF_TARGET_ESP32)
left_pad_offset = maxWords_sz << 2;
if (left_pad_offset <= 512 >> 3) {
left_pad_offset = 512 >> 3;
}
else {
if (left_pad_offset <= 1024 >> 3) {
left_pad_offset = 1024 >> 3;
}
else {
if (left_pad_offset <= 1536 >> 3) {
left_pad_offset = 1536 >> 3;
}
else {
if (left_pad_offset <= 2048 >> 3) {
left_pad_offset = 2048 >> 3;
}
else {
ret = MP_VAL;
ESP_LOGE(TAG, "Unsupported operand length: %d",
hwWords_sz);
}
}
}
}
if (ret == MP_OKAY) {
mp_mul_lock_called = TRUE;
#ifdef WOLFSSL_HW_METRICS
{
esp_mp_max_used = (X->used > esp_mp_max_used) ? X->used :
esp_mp_max_used;
esp_mp_max_used = (Y->used > esp_mp_max_used) ? Y->used :
esp_mp_max_used;
}
#endif
ret = esp_mp_hw_lock();
}
if (ret == MP_OKAY) {
ret = esp_mp_hw_wait_clean();
}
if (ret == MP_OKAY) {
DPORT_REG_WRITE(RSA_MULT_MODE_REG,
(2 * left_pad_offset * 8 / 512) - 1 + 8);
esp_mpint_to_memblock(RSA_MEM_X_BLOCK_BASE,
X,
Xs,
hwWords_sz);
esp_zero_memblock(RSA_MEM_Z_BLOCK_BASE,
(left_pad_offset - 1) / sizeof(int));
esp_mpint_to_memblock(RSA_MEM_Z_BLOCK_BASE + (left_pad_offset),
Y,
Ys,
hwWords_sz);
#ifdef DEBUG_WOLFSSL
esp_memblock_to_mpint(RSA_MEM_Z_BLOCK_BASE,
PEEK,
128);
#endif
process_start(RSA_MULT_START_REG);
ret = wait_until_done(RSA_INTERRUPT_REG);
if (ret == MP_OKAY) {
esp_memblock_to_mpint(RSA_MEM_Z_BLOCK_BASE, Z, resultWords_sz);
}
#ifndef DEBUG_WOLFSSL
else {
ESP_LOGE(TAG, "ERROR: wait_until_done failed in esp32_mp");
}
#endif
}
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
if ((hwWords_sz * BITS_IN_ONE_WORD) > ESP_HW_MULTI_RSAMAX_BITS) {
#ifdef WOLFSSL_DEBUG_ESP_HW_MULTI_RSAMAX_BITS
ESP_LOGW(TAG, "exceeds max bit length(%d)",
ESP_HW_MULTI_RSAMAX_BITS);
#endif
ret = MP_HW_FALLBACK;
}
if ((hwWords_sz * BITS_IN_ONE_WORD * 2) > ESP_HW_RSAMAX_BIT) {
#ifdef WOLFSSL_DEBUG_ESP_HW_MULTI_RSAMAX_BITS
ESP_LOGW(TAG, "result exceeds max bit length(%d) * 2",
ESP_HW_RSAMAX_BIT );
#endif
ret = MP_HW_FALLBACK;
}
if (ret == MP_OKAY) {
mp_mul_lock_called = TRUE;
#ifdef WOLFSSL_HW_METRICS
{
esp_mp_max_used = (X->used > esp_mp_max_used) ? X->used :
esp_mp_max_used;
esp_mp_max_used = (Y->used > esp_mp_max_used) ? Y->used :
esp_mp_max_used;
}
#endif
ret = esp_mp_hw_lock();
}
if (ret == MP_OKAY) {
ret = esp_mp_hw_wait_clean();
}
if (ret == MP_OKAY) {
DPORT_REG_WRITE(RSA_INTERRUPT_REG, 0);
DPORT_REG_WRITE(RSA_LENGTH_REG, (hwWords_sz * 2 - 1));
esp_mpint_to_memblock(RSA_MEM_X_BLOCK_BASE,
X,
Xs,
hwWords_sz);
esp_mpint_to_memblock(RSA_MEM_Z_BLOCK_BASE + hwWords_sz * 4,
Y,
Ys,
hwWords_sz);
process_start(RSA_MULT_START_REG);
ret = wait_until_done(RSA_QUERY_INTERRUPT_REG);
}
if (ret == MP_OKAY) {
esp_memblock_to_mpint(RSA_MEM_Z_BLOCK_BASE, Z, resultWords_sz);
}
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
if ((hwWords_sz * BITS_IN_ONE_WORD) > ESP_HW_MULTI_RSAMAX_BITS) {
#ifdef WOLFSSL_DEBUG_ESP_HW_MULTI_RSAMAX_BITS
ESP_LOGW(TAG, "RSA mul result hwWords_sz %d exceeds max bit length %d",
hwWords_sz, ESP_HW_MULTI_RSAMAX_BITS);
#endif
ret = MP_HW_FALLBACK;
}
if ((hwWords_sz * BITS_IN_ONE_WORD * 2) > ESP_HW_RSAMAX_BIT) {
#ifdef WOLFSSL_DEBUG_ESP_HW_MULTI_RSAMAX_BITS
ESP_LOGW(TAG, "RSA max result hwWords_sz %d exceeds max bit length %d",
hwWords_sz, ESP_HW_RSAMAX_BIT );
#endif
ret = MP_HW_FALLBACK;
}
if (ret == MP_OKAY) {
mp_mul_lock_called = TRUE;
#ifdef WOLFSSL_HW_METRICS
{
esp_mp_max_used = (X->used > esp_mp_max_used) ? X->used :
esp_mp_max_used;
esp_mp_max_used = (Y->used > esp_mp_max_used) ? Y->used :
esp_mp_max_used;
}
#endif
ret = esp_mp_hw_lock();
}
if (ret == MP_OKAY) {
ret = esp_mp_hw_wait_clean();
}
if (ret == MP_OKAY) {
DPORT_REG_WRITE(RSA_INT_ENA_REG, 0);
DPORT_REG_WRITE(RSA_MODE_REG, (hwWords_sz * 2 - 1));
esp_mpint_to_memblock(RSA_X_MEM,
X,
Xs,
hwWords_sz);
esp_mpint_to_memblock(RSA_Z_MEM + hwWords_sz * 4,
Y,
Ys,
hwWords_sz);
ret = process_start(RSA_SET_START_MULT_REG);
}
if (ret == MP_OKAY) {
ret = wait_until_done(RSA_QUERY_IDLE_REG);
}
if (ret == MP_OKAY) {
esp_memblock_to_mpint(RSA_Z_MEM, Z, resultWords_sz);
}
#elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
if ((hwWords_sz * BITS_IN_ONE_WORD) > ESP_HW_MULTI_RSAMAX_BITS) {
#ifdef WOLFSSL_DEBUG_ESP_HW_MULTI_RSAMAX_BITS
ESP_LOGW(TAG, "exceeds max bit length(%d)", ESP_HW_MULTI_RSAMAX_BITS);
#endif
ret = MP_HW_FALLBACK;
}
if ((hwWords_sz * BITS_IN_ONE_WORD * 2) > ESP_HW_RSAMAX_BIT) {
#ifdef WOLFSSL_DEBUG_ESP_HW_MULTI_RSAMAX_BITS
ESP_LOGW(TAG, "result exceeds max bit length(%d)", ESP_HW_RSAMAX_BIT );
#endif
ret = MP_HW_FALLBACK;
}
if (ret == MP_OKAY) {
mp_mul_lock_called = TRUE;
#ifdef WOLFSSL_HW_METRICS
{
esp_mp_max_used = (X->used > esp_mp_max_used) ? X->used :
esp_mp_max_used;
esp_mp_max_used = (Y->used > esp_mp_max_used) ? Y->used :
esp_mp_max_used;
}
#endif
ret = esp_mp_hw_lock();
}
if (ret == MP_OKAY) {
ret = esp_mp_hw_wait_clean();
}
if (ret == MP_OKAY) {
DPORT_REG_WRITE(RSA_INTERRUPT_REG, 0);
DPORT_REG_WRITE(RSA_LENGTH_REG, (hwWords_sz * 2 - 1));
esp_mpint_to_memblock(RSA_MEM_X_BLOCK_BASE,
X,
Xs,
hwWords_sz);
esp_mpint_to_memblock(RSA_MEM_Z_BLOCK_BASE + hwWords_sz * 4,
Y,
Ys,
hwWords_sz);
process_start(RSA_MULT_START_REG);
ret = wait_until_done(RSA_QUERY_INTERRUPT_REG);
}
if (ret == MP_OKAY) {
esp_memblock_to_mpint(RSA_MEM_Z_BLOCK_BASE, Z, resultWords_sz);
}
#else
ret = MP_HW_FALLBACK;
#endif
if (mp_mul_lock_called) {
ret = esp_mp_hw_unlock();
}
else {
ESP_LOGV(TAG, "Lock not called");
}
#if defined(WOLFSSL_SP_INT_NEGATIVE) || defined(USE_FAST_MATH)
if (ret == MP_OKAY) {
if (!mp_iszero(Z) && res_sign) {
ESP_LOGV(TAG, "Setting Z to negative result!");
mp_setneg(Z);
}
else {
Z->sign = MP_ZPOS;
}
}
#endif
if (ret == MP_OKAY) {
esp_clean_result(Z, 0);
}
#ifdef DEBUG_WOLFSSL
if (mp_cmp(X, X2) != 0) {
}
if (mp_cmp(Y, Y2) != 0) {
}
if (mp_cmp(Z, Z2) != 0) {
int found_z_used = Z->used;
ESP_LOGE(TAG, "mp_mul Z vs Z2 mismatch!");
ESP_LOGI(TAG, "Xs = %d", Xs);
ESP_LOGI(TAG, "Ys = %d", Ys);
ESP_LOGI(TAG, "Zs = %d", Zs);
ESP_LOGI(TAG, "found_z_used = %d", found_z_used);
ESP_LOGI(TAG, "z.used = %d", Z->used);
ESP_LOGI(TAG, "hwWords_sz = %d", hwWords_sz);
ESP_LOGI(TAG, "maxWords_sz = %d", maxWords_sz);
#if defined(CONFIG_IDF_TARGET_ESP32)
ESP_LOGI(TAG, "left_pad_offset = %d", left_pad_offset);
#endif
ESP_LOGI(TAG, "hwWords_sz<<2 = %d", hwWords_sz << 2);
esp_show_mp("X", X2);
esp_show_mp("Y", Y2);
esp_show_mp("Peek Z", PEEK);
esp_show_mp("Z", Z);
esp_show_mp("Z2", Z2);
#ifndef NO_RECOVER_SOFTWARE_CALC
ESP_LOGW(TAG, "Recovering mp_mul error with software result");
mp_copy(Z2, Z);
#else
ret = MP_VAL;
#endif
}
#endif
#ifdef WOLFSSL_HW_METRICS
esp_mp_mul_usage_ct++;
esp_mp_max_used = (Z->used > esp_mp_max_used) ? Z->used : esp_mp_max_used;
if (ret != MP_OKAY) {
esp_mp_mul_error_ct++;
}
#endif
ESP_LOGV(TAG, "\nEnd esp_mp_mul \n");
return ret;
}
#endif
#ifndef NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD
int esp_mp_mulmod(MATH_INT_T* X, MATH_INT_T* Y, MATH_INT_T* M, MATH_INT_T* Z)
{
struct esp_mp_helper mph[1];
MATH_INT_T tmpZ[1] = { };
#ifdef DEBUG_WOLFSSL
MATH_INT_T X2[1] = { };
MATH_INT_T Y2[1] = { };
MATH_INT_T M2[1] = { };
MATH_INT_T Z2[1] = { };
MATH_INT_T PEEK[1] = { };
(void) PEEK;
#endif
int ret = MP_OKAY;
int mulmod_lock_called = FALSE;
word32 zwords = 0;
#if defined(WOLFSSL_SP_INT_NEGATIVE) || defined(USE_FAST_MATH)
int negcheck = 0;
#endif
#ifdef DEBUG_WOLFSSL
int reti = 0;
#endif
#if defined(CONFIG_IDF_TARGET_ESP32)
#elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6)
word32 OperandBits;
int WordsForOperand;
#elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
word32 OperandBits;
int WordsForOperand;
#else
ret = MP_HW_FALLBACK;
#endif
ESP_LOGV(TAG, "\nBegin esp_mp_mulmod \n");
if ((M->dp[0] & 1) == 0) {
#ifndef NO_ESP_MP_MUL_EVEN_ALT_CALC
#if defined(NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL)
ret = mp_mul(X, Y, tmpZ);
#else
ret = esp_mp_mul(X, Y, tmpZ);
#endif
if (ret == MP_OKAY) {
ret = mp_mod(tmpZ, M, Z);
}
ESP_LOGV(TAG, "alternate mp_mul calc!");
return ret;
#else
#ifdef WOLFSSL_HW_METRICS
esp_mp_mulmod_even_mod_ct++;
#endif
ESP_LOGV(TAG, "esp_mp_mulmod does not support even numbers");
ret = MP_HW_FALLBACK;
return ret;
#endif
}
#ifdef DEBUG_WOLFSSL
if (esp_hw_validation_active()) {
ESP_LOGV(TAG, "MP_HW_VALIDATION_ACTIVE");
return MP_HW_VALIDATION_ACTIVE;
}
#endif
#ifdef DEBUG_WOLFSSL
if (IS_HW_VALIDATION) {
ESP_LOGE(TAG, "Caller must not try HW when validation active.");
}
else {
mp_init(X2);
mp_init(Y2);
mp_init(M2);
mp_init(Z2);
mp_copy(X, X2);
mp_copy(Y, Y2);
mp_copy(M, M2);
mp_copy(Z, Z2);
SET_HW_VALIDATION;
reti = mp_mulmod(X2, Y2, M2, Z2);
if (reti == 0) {
ESP_LOGV(TAG, "wolfSSL mp_mulmod during validation success");
}
else {
ESP_LOGE(TAG, "wolfSSL mp_mulmod during validation failed");
}
CLR_HW_VALIDATION;
}
#endif
if (ret == MP_OKAY) {
#if defined(WOLFSSL_SP_INT_NEGATIVE) || defined(USE_FAST_MATH)
negcheck = mp_isneg(X) != mp_isneg(Y) ? 1 : 0;
#endif
ret = esp_mp_montgomery_init(X, Y, M, mph);
if (ret == MP_OKAY) {
ESP_LOGV(TAG, "esp_mp_exptmod esp_mp_montgomery_init success.");
}
else {
#ifdef WOLFSSL_HW_METRICS
if (ret == MP_HW_FALLBACK) {
esp_mp_mulmod_fallback_ct++;
}
else {
esp_mp_mulmod_error_ct++;
}
#endif
return ret;
}
zwords = bits2words(min(mph->Ms, mph->Xs + mph->Ys));
}
if (mph->Xs <= ESP_RSA_MULM_BITS || mph->Ys <= ESP_RSA_MULM_BITS) {
#ifdef WOLFSSL_HW_METRICS
{
esp_mp_mulmod_small_y_ct++;
}
#endif
ret = MP_HW_FALLBACK;
#ifdef WOLFSSL_DEBUG_ESP_RSA_MULM_BITS
{
ESP_LOGW(TAG, "esp_mp_mulmod falling back for ESP_RSA_MULM_BITS!");
}
#endif
}
if (ret == MP_OKAY) {
#ifdef WOLFSSL_HW_METRICS
{
esp_mp_max_used = (X->used > esp_mp_max_used) ? X->used :
esp_mp_max_used;
esp_mp_max_used = (Y->used > esp_mp_max_used) ? Y->used :
esp_mp_max_used;
esp_mp_max_used = (M->used > esp_mp_max_used) ? M->used :
esp_mp_max_used;
}
#endif
ret = esp_mp_hw_lock();
if (ret == ESP_OK) {
mulmod_lock_called = TRUE;
}
else {
ret = WC_HW_WAIT_E;
}
}
#if defined(CONFIG_IDF_TARGET_ESP32)
if (ret == MP_OKAY) {
ret = esp_mp_hw_wait_clean();
}
if (ret == MP_OKAY) {
DPORT_REG_WRITE(RSA_MULT_MODE_REG, (mph->hwWords_sz >> 4) - 1);
#if defined(DEBUG_WOLFSSL)
ESP_LOGV(TAG, "RSA_MULT_MODE_REG = %d", (mph->hwWords_sz >> 4) - 1);
#endif
esp_mpint_to_memblock(RSA_MEM_X_BLOCK_BASE,
X, mph->Xs, mph->hwWords_sz);
esp_mpint_to_memblock(RSA_MEM_M_BLOCK_BASE,
M, mph->Ms, mph->hwWords_sz);
esp_mpint_to_memblock(RSA_MEM_Z_BLOCK_BASE,
&(mph->r_inv), mph->Rs, mph->hwWords_sz);
DPORT_REG_WRITE(RSA_M_DASH_REG, mph->mp);
ESP_EM__3_16;
process_start(RSA_MULT_START_REG);
wait_until_done(RSA_INTERRUPT_REG);
esp_mpint_to_memblock(RSA_MEM_X_BLOCK_BASE,
Y, mph->Ys,
mph->hwWords_sz);
#ifdef DEBUG_WOLFSSL
esp_memblock_to_mpint(RSA_MEM_X_BLOCK_BASE,
PEEK,
128);
esp_clean_result(PEEK, 0);
#endif
process_start(RSA_MULT_START_REG);
wait_until_done(RSA_INTERRUPT_REG);
esp_memblock_to_mpint(RSA_MEM_Z_BLOCK_BASE, tmpZ, zwords);
}
if (mulmod_lock_called) {
ret = esp_mp_hw_unlock();
}
else {
ESP_LOGV(TAG, "Lock not called");
}
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
if (ret == MP_OKAY) {
ret = esp_mp_hw_wait_clean();
}
if (ret == MP_OKAY) {
DPORT_REG_WRITE(RSA_INTERRUPT_REG, 0);
OperandBits = max(max(mph->Xs, mph->Ys), mph->Ms);
if (OperandBits > ESP_HW_MOD_RSAMAX_BITS) {
#ifdef WOLFSSL_DEBUG_ESP_HW_MOD_RSAMAX_BITS
ESP_LOGW(TAG, "result exceeds max bit length");
#endif
if (mulmod_lock_called) {
esp_mp_hw_unlock();
}
return MP_HW_FALLBACK;
}
WordsForOperand = bits2words(OperandBits);
DPORT_REG_WRITE(RSA_LENGTH_REG, WordsForOperand - 1);
DPORT_REG_WRITE(RSA_M_DASH_REG, mph->mp);
DPORT_REG_WRITE(RSA_CONSTANT_TIME_REG, 0);
esp_mpint_to_memblock(RSA_MEM_X_BLOCK_BASE,
X,
mph->Xs,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_MEM_Y_BLOCK_BASE,
Y,
mph->Ys,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_MEM_M_BLOCK_BASE,
M,
mph->Ms,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_MEM_RB_BLOCK_BASE,
&(mph->r_inv),
mph->Rs,
mph->hwWords_sz);
process_start(RSA_MOD_MULT_START_REG);
}
if (ret == MP_OKAY) {
ret = wait_until_done(RSA_QUERY_INTERRUPT_REG);
}
if (ret == MP_OKAY) {
esp_memblock_to_mpint(RSA_MEM_Z_BLOCK_BASE, tmpZ, zwords);
}
if (mulmod_lock_called) {
ret = esp_mp_hw_unlock();
}
else {
ESP_LOGV(TAG, "Lock not called, esp_mp_hw_unlock skipped");
}
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
if (ret == MP_OKAY) {
ret = esp_mp_hw_wait_clean();
}
if (ret == MP_OKAY) {
DPORT_REG_WRITE(RSA_INT_ENA_REG, 0);
OperandBits = max(max(mph->Xs, mph->Ys), mph->Ms);
if (OperandBits > ESP_HW_MOD_RSAMAX_BITS) {
#ifdef WOLFSSL_DEBUG_ESP_HW_MOD_RSAMAX_BITS
ESP_LOGW(TAG, "mulmod OperandBits = %d "
"result exceeds max bit length %d",
OperandBits, ESP_HW_MOD_RSAMAX_BITS);
#endif
if (mulmod_lock_called) {
esp_mp_hw_unlock();
}
return MP_HW_FALLBACK;
}
WordsForOperand = bits2words(OperandBits);
DPORT_REG_WRITE(RSA_MODE_REG, WordsForOperand - 1);
DPORT_REG_WRITE(RSA_M_PRIME_REG, mph->mp);
DPORT_REG_WRITE(RSA_CONSTANT_TIME_REG, 0);
DPORT_REG_WRITE(RSA_SEARCH_POS_REG, 0);
esp_mpint_to_memblock(RSA_X_MEM,
X,
mph->Xs,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_Y_MEM,
Y,
mph->Ys,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_M_MEM,
M,
mph->Ms,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_Z_MEM,
&(mph->r_inv),
mph->Rs,
mph->hwWords_sz);
process_start(RSA_SET_START_MODMULT_REG);
}
if (ret == MP_OKAY) {
ret = wait_until_done(RSA_QUERY_IDLE_REG);
}
if (ret == MP_OKAY) {
esp_memblock_to_mpint(RSA_Z_MEM, tmpZ, zwords);
}
if (mulmod_lock_called) {
ret = esp_mp_hw_unlock();
}
else {
ESP_LOGV(TAG, "Lock not called, esp_mp_hw_unlock skipped");
}
#elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
if (ret == MP_OKAY) {
ret = esp_mp_hw_wait_clean();
}
if (ret == MP_OKAY) {
DPORT_REG_WRITE(RSA_INTERRUPT_REG, 0);
OperandBits = max(max(mph->Xs, mph->Ys), mph->Ms);
if (OperandBits > ESP_HW_MOD_RSAMAX_BITS) {
#ifdef WOLFSSL_DEBUG_ESP_HW_MOD_RSAMAX_BITS
ESP_LOGW(TAG, "mp_mulmod OperandBits %d exceeds max bit length %d.",
OperandBits, ESP_HW_MOD_RSAMAX_BITS);
#endif
if (mulmod_lock_called) {
esp_mp_hw_unlock();
}
return MP_HW_FALLBACK;
}
WordsForOperand = bits2words(OperandBits);
DPORT_REG_WRITE(RSA_LENGTH_REG, WordsForOperand - 1);
DPORT_REG_WRITE(RSA_M_DASH_REG, mph->mp);
DPORT_REG_WRITE(RSA_CONSTANT_TIME_REG, 0);
esp_mpint_to_memblock(RSA_MEM_X_BLOCK_BASE,
X,
mph->Xs,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_MEM_Y_BLOCK_BASE,
Y,
mph->Ys,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_MEM_M_BLOCK_BASE,
M,
mph->Ms,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_MEM_RB_BLOCK_BASE,
&(mph->r_inv),
mph->Rs,
mph->hwWords_sz);
process_start(RSA_MOD_MULT_START_REG);
asm volatile("memw");
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");
}
if (ret == MP_OKAY) {
ret = wait_until_done(RSA_QUERY_INTERRUPT_REG);
}
if (ret == MP_OKAY) {
esp_memblock_to_mpint(RSA_MEM_Z_BLOCK_BASE, tmpZ, zwords);
}
if (mulmod_lock_called) {
ret = esp_mp_hw_unlock();
}
else {
if (ret == MP_HW_FALLBACK) {
ESP_LOGV(TAG, "Lock not called due to no-lock MP_HW_FALLBACK");
}
else {
#ifdef WOLFSSL_ESP32_HW_LOCK_DEBUG
ESP_LOGW(TAG, "Lock unexpectedly not called for mp_mulmod");
#endif
}
}
#else
ret = MP_HW_FALLBACK;
#endif
if (ret == MP_OKAY) {
if (mp_cmp(tmpZ, M) == MP_GT) {
mp_sub(tmpZ, M, tmpZ);
ESP_LOGV(TAG, "Z is greater than M");
}
#if defined(WOLFSSL_SP_INT_NEGATIVE) || defined(USE_FAST_MATH)
if (negcheck) {
mp_sub(M, tmpZ, tmpZ);
ESP_LOGV(TAG, "neg check adjustment");
}
#endif
mp_copy(tmpZ, Z);
esp_clean_result(Z, 0);
}
#ifdef WOLFSSL_HW_METRICS
esp_mp_mulmod_usage_ct++;
if (ret == MP_HW_FALLBACK) {
ESP_LOGV(TAG, "esp_mp_mulmod HW Fallback tick");
esp_mp_mulmod_fallback_ct++;
}
#endif
#ifdef DEBUG_WOLFSSL
if (ret == MP_HW_FALLBACK) {
ESP_LOGI(TAG, "HW Fallback");
}
else {
if (mp_cmp(X, X2) != 0) {
ESP_LOGV(TAG, "mp_mul X vs X2 mismatch!");
}
if (mp_cmp(Y, Y2) != 0) {
ESP_LOGV(TAG, "mp_mul Y vs Y2 mismatch!");
}
if (mp_cmp(Z, Z2) != 0) {
ESP_LOGE(TAG, "esp_mp_mulmod Z vs Z2 mismatch!");
esp_mp_mulmod_error_ct++;
int found_z_used = Z->used;
ESP_LOGI(TAG, "Xs = %d", mph->Xs);
ESP_LOGI(TAG, "Ys = %d", mph->Ys);
ESP_LOGI(TAG, "found_z_used = %d", found_z_used);
ESP_LOGI(TAG, "z.used = %d", Z->used);
ESP_LOGI(TAG, "hwWords_sz = %d", mph->hwWords_sz);
ESP_LOGI(TAG, "maxWords_sz = %d", mph->maxWords_sz);
ESP_LOGI(TAG, "hwWords_sz<<2 = %d", mph->hwWords_sz << 2);
esp_show_mp("X", X2);
esp_show_mp("Y", Y2);
esp_show_mp("M", M2);
ESP_LOGI(TAG, "Xs = %d", mph->Xs);
ESP_LOGI(TAG, "Ys = %d", mph->Ys);
ESP_LOGI(TAG, "found_z_used = %d", found_z_used);
ESP_LOGI(TAG, "z.used = %d", Z->used);
ESP_LOGI(TAG, "hwWords_sz = %d", mph->hwWords_sz);
ESP_LOGI(TAG, "maxWords_sz = %d", mph->maxWords_sz);
ESP_LOGI(TAG, "hwWords_sz<<2 = %d", mph->hwWords_sz << 2);
esp_show_mp("X", X2);
esp_show_mp("Y", Y2);
esp_show_mp("M", M2);
esp_show_mp("r_inv", &(mph->r_inv));
ESP_LOGI(TAG, "mp = 0x%08x = %u", mph->mp, mph->mp);
if (mph->mp == mph->mp2) {
ESP_LOGI(TAG, "M' match esp_calc_Mdash vs mp_montgomery_setup"
" = %d !", mph->mp);
}
else {
ESP_LOGW(TAG,
"\n\n"
"M' MISMATCH esp_calc_Mdash = 0x%08x = %d \n"
"vs mp_montgomery_setup = 0x%08x = %d \n\n",
mph->mp,
mph->mp,
mph->mp2,
mph->mp2);
mph->mp = mph->mp2;
}
esp_show_mp("HW Z", Z);
esp_show_mp("SW Z2", Z2);
ESP_LOGI(TAG, "esp_mp_mulmod_usage_ct = %lu tries",
esp_mp_mulmod_usage_ct);
ESP_LOGI(TAG, "esp_mp_mulmod_error_ct = %lu failures",
esp_mp_mulmod_error_ct);
ESP_LOGI(TAG, WOLFSSL_ESPIDF_BLANKLINE_MESSAGE);
esp_show_mp("HW Z", Z);
esp_show_mp("SW Z2", Z2);
ESP_LOGI(TAG, "esp_mp_mulmod_usage_ct = %lu tries",
esp_mp_mulmod_usage_ct);
ESP_LOGI(TAG, "esp_mp_mulmod_error_ct = %lu failures",
esp_mp_mulmod_error_ct);
ESP_LOGI(TAG, WOLFSSL_ESPIDF_BLANKLINE_MESSAGE);
#ifndef NO_RECOVER_SOFTWARE_CALC
{
ESP_LOGW(TAG, "Recovering mp_mul error with software result");
mp_copy(Z2, Z);
}
#else
{
ret = MP_VAL;
}
#endif
}
else {
ESP_LOGV(TAG, "esp_mp_mulmod success!");
}
}
#endif
mp_clear(tmpZ);
mp_clear(&(mph->r_inv));
ESP_LOGV(TAG, "\nEnd esp_mp_mulmod \n");
if (ret == MP_OKAY || ret == MP_HW_FALLBACK) {
ESP_LOGV(TAG, "esp_mp_mulmod exit success ");
}
else {
ESP_LOGW(TAG, "esp_mp_mulmod exit failed = %d", ret);
}
#ifdef WOLFSSL_HW_METRICS
esp_mp_max_used = (Z->used > esp_mp_max_used) ? Z->used : esp_mp_max_used;
#endif
return ret;
}
#endif
#ifndef NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD
int esp_mp_exptmod(MATH_INT_T* X, MATH_INT_T* Y, MATH_INT_T* M, MATH_INT_T* Z)
{
struct esp_mp_helper mph[1];
int ret = MP_OKAY;
int exptmod_lock_called = FALSE;
#if defined(CONFIG_IDF_TARGET_ESP32)
#elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6)
word32 OperandBits;
word32 WordsForOperand;
#elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
word32 OperandBits;
word32 WordsForOperand;
#else
#endif
ESP_LOGV(TAG, "\nBegin esp_mp_exptmod \n");
#ifdef WOLFSSL_HW_METRICS
esp_mp_exptmod_usage_ct++;
esp_mp_max_used = (X->used > esp_mp_max_used) ? X->used : esp_mp_max_used;
esp_mp_max_used = (Y->used > esp_mp_max_used) ? Y->used : esp_mp_max_used;
esp_mp_max_used = (M->used > esp_mp_max_used) ? M->used : esp_mp_max_used;
#endif
if (mp_iszero(M)) {
#ifdef DEBUG_WOLFSSL
ESP_LOGI(TAG, "esp_mp_exptmod M is zero!");
#endif
#ifdef WOLFSSL_HW_METRICS
esp_mp_exptmod_fallback_ct++;
#endif
return MP_HW_FALLBACK;
}
if (mp_isone(M)) {
#ifdef DEBUG_WOLFSSL
ESP_LOGI(TAG, "esp_mp_exptmod M is one!");
#endif
mp_clear(Z);
return MP_OKAY;
}
ret = esp_mp_montgomery_init(X, Y, M, mph);
if (ret == MP_OKAY) {
ESP_LOGV(TAG, "esp_mp_exptmod esp_mp_montgomery_init success.");
}
else {
#ifdef WOLFSSL_HW_METRICS
if (ret == MP_HW_FALLBACK) {
esp_mp_exptmod_fallback_ct++;
}
else {
esp_mp_exptmod_error_ct++;
}
#endif
return ret;
}
#ifdef DEBUG_WOLFSSL
if (esp_hw_validation_active()) {
return MP_HW_VALIDATION_ACTIVE;
}
if (esp_mp_exptmod_depth_counter != 0) {
ESP_LOGE(TAG, "esp_mp_exptmod Depth Counter Error!");
}
esp_mp_exptmod_depth_counter++;
#endif
if (ret == MP_OKAY) {
exptmod_lock_called = TRUE;
#ifdef WOLFSSL_HW_METRICS
{
esp_mp_max_used = (X->used > esp_mp_max_used) ? X->used :
esp_mp_max_used;
esp_mp_max_used = (Y->used > esp_mp_max_used) ? Y->used :
esp_mp_max_used;
}
#endif
ret = esp_mp_hw_lock();
if (ret != MP_OKAY) {
ESP_LOGE(TAG, "esp_mp_hw_lock failed");
#ifdef DEBUG_WOLFSSL
esp_mp_exptmod_depth_counter--;
#endif
return MP_HW_FALLBACK;
}
}
#if defined(CONFIG_IDF_TARGET_ESP32)
if (ret == MP_OKAY) {
ret = esp_mp_hw_wait_clean();
#ifdef WOLFSSL_HW_METRICS
if (ret != MP_OKAY) {
esp_mp_exptmod_error_ct++;
}
#endif
}
if (ret == MP_OKAY) {
ESP_LOGV(TAG,
"hwWords_sz = %d, num = %d",
mph->hwWords_sz,
(mph->hwWords_sz >> 4) - 1
);
DPORT_REG_WRITE(RSA_MODEXP_MODE_REG, (mph->hwWords_sz >> 4) - 1);
esp_mpint_to_memblock(RSA_MEM_X_BLOCK_BASE,
X,
mph->Xs,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_MEM_Y_BLOCK_BASE,
Y, mph->Ys,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_MEM_M_BLOCK_BASE,
M,
mph->Ms,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_MEM_Z_BLOCK_BASE,
&(mph->r_inv),
mph->Rs,
mph->hwWords_sz);
ESP_LOGV(TAG, "M' = %d", mph->mp);
DPORT_REG_WRITE(RSA_M_DASH_REG, mph->mp);
ESP_EM__3_16;
process_start(RSA_MODEXP_START_REG);
wait_until_done(RSA_INTERRUPT_REG);
esp_memblock_to_mpint(RSA_MEM_Z_BLOCK_BASE, Z, BITS_TO_WORDS(mph->Ms));
}
if (exptmod_lock_called) {
ret = esp_mp_hw_unlock();
}
else {
ESP_LOGV(TAG, "Lock not called");
}
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
OperandBits = max(max(mph->Xs, mph->Ys), mph->Ms);
if (OperandBits > ESP_HW_MOD_RSAMAX_BITS) {
#ifdef WOLFSSL_HW_METRICS
ESP_LOGW(TAG, "exptmod operand bits %d exceeds max bit length %d",
OperandBits, ESP_HW_MOD_RSAMAX_BITS);
esp_mp_mulmod_max_exceeded_ct++;
#endif
if (exptmod_lock_called) {
ret = esp_mp_hw_unlock();
}
ESP_LOGV(TAG, "Return esp_mp_exptmod fallback");
return MP_HW_FALLBACK;
}
else {
WordsForOperand = bits2words(OperandBits);
}
if (ret == MP_OKAY) {
ret = esp_mp_hw_wait_clean();
}
if (ret == MP_OKAY) {
DPORT_REG_WRITE(RSA_INTERRUPT_REG, 0);
DPORT_REG_WRITE(RSA_LENGTH_REG, WordsForOperand - 1);
DPORT_REG_WRITE(RSA_M_DASH_REG, mph->mp);
esp_mpint_to_memblock(RSA_MEM_X_BLOCK_BASE,
X,
mph->Xs,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_MEM_Y_BLOCK_BASE,
Y,
mph->Ys,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_MEM_M_BLOCK_BASE,
M,
mph->Ms,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_MEM_Z_BLOCK_BASE,
&(mph->r_inv),
mph->Rs,
mph->hwWords_sz);
process_start(RSA_MODEXP_START_REG);
ret = wait_until_done(RSA_QUERY_INTERRUPT_REG);
}
if (MP_OKAY == ret) {
esp_memblock_to_mpint(RSA_MEM_Z_BLOCK_BASE, Z, BITS_TO_WORDS(mph->Ms));
}
if (exptmod_lock_called) {
ret = esp_mp_hw_unlock();
}
else {
ESP_LOGV(TAG, "Lock not called");
}
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
OperandBits = max(max(mph->Xs, mph->Ys), mph->Ms);
if (OperandBits > ESP_HW_MOD_RSAMAX_BITS) {
#ifdef WOLFSSL_HW_METRICS
ESP_LOGW(TAG, "exptmod operand bits %d exceeds max bit length %d",
OperandBits, ESP_HW_MOD_RSAMAX_BITS);
esp_mp_mulmod_max_exceeded_ct++;
#endif
if (exptmod_lock_called) {
ret = esp_mp_hw_unlock();
}
ESP_LOGV(TAG, "Return esp_mp_exptmod fallback");
return MP_HW_FALLBACK;
}
else {
WordsForOperand = bits2words(OperandBits);
}
if (ret == MP_OKAY) {
ret = esp_mp_hw_wait_clean();
}
if (ret == MP_OKAY) {
DPORT_REG_WRITE(RSA_INT_ENA_REG, 0);
DPORT_REG_WRITE(RSA_MODE_REG, WordsForOperand - 1);
DPORT_REG_WRITE(RSA_M_PRIME_REG, mph->mp);
esp_mpint_to_memblock(RSA_X_MEM,
X,
mph->Xs,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_Y_MEM,
Y,
mph->Ys,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_M_MEM,
M,
mph->Ms,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_Z_MEM,
&(mph->r_inv),
mph->Rs,
mph->hwWords_sz);
process_start(RSA_SET_START_MODEXP_REG);
ret = wait_until_done(RSA_QUERY_IDLE_REG);
}
if (MP_OKAY == ret) {
esp_memblock_to_mpint(RSA_Z_MEM, Z, BITS_TO_WORDS(mph->Ms));
}
#ifdef WOLFSSL_ESP32_HW_LOCK_DEBUG
ESP_LOGI(TAG, "Unlock esp_mp_exptmod");
#endif
if (exptmod_lock_called) {
ret = esp_mp_hw_unlock();
}
else {
#ifdef WOLFSSL_ESP32_HW_LOCK_DEBUG
ESP_LOGV(TAG, "Lock not called");
#endif
}
#elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
if (ret == MP_OKAY) {
ret = esp_mp_hw_wait_clean();
}
if (ret == MP_OKAY) {
OperandBits = max(max(mph->Xs, mph->Ys), mph->Ms);
if (OperandBits > ESP_HW_MOD_RSAMAX_BITS) {
#ifdef WOLFSSL_DEBUG_ESP_HW_MOD_RSAMAX_BITS
ESP_LOGW(TAG, "exptmod operand bits %d exceeds max bit length %d",
OperandBits, ESP_HW_MOD_RSAMAX_BITS);
#endif
ret = MP_HW_FALLBACK;
}
else {
WordsForOperand = bits2words(OperandBits);
}
}
if (ret == MP_OKAY) {
DPORT_REG_WRITE(RSA_INTERRUPT_REG, 0);
DPORT_REG_WRITE(RSA_LENGTH_REG, WordsForOperand - 1);
DPORT_REG_WRITE(RSA_M_DASH_REG, mph->mp);
esp_mpint_to_memblock(RSA_MEM_X_BLOCK_BASE,
X,
mph->Xs,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_MEM_Y_BLOCK_BASE,
Y,
mph->Ys,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_MEM_M_BLOCK_BASE,
M,
mph->Ms,
mph->hwWords_sz);
esp_mpint_to_memblock(RSA_MEM_Z_BLOCK_BASE,
&(mph->r_inv),
mph->Rs,
mph->hwWords_sz);
process_start(RSA_MODEXP_START_REG);
ret = wait_until_done(RSA_QUERY_INTERRUPT_REG);
}
if (MP_OKAY == ret) {
esp_memblock_to_mpint(RSA_MEM_Z_BLOCK_BASE, Z, BITS_TO_WORDS(mph->Ms));
}
if (exptmod_lock_called) {
ret = esp_mp_hw_unlock();
}
else {
ESP_LOGV(TAG, "Lock not called");
}
#else
ret = MP_HW_FALLBACK;
#endif
#ifdef DEBUG_WOLFSSL
if (esp_mp_exptmod_depth_counter != 1) {
ESP_LOGE(TAG, "esp_mp_exptmod exit Depth Counter Error!");
}
esp_mp_exptmod_depth_counter--;
#endif
if (ret == MP_OKAY) {
esp_clean_result(Z, 0);
}
#ifdef WOLFSSL_HW_METRICS
esp_mp_max_used = (Z->used > esp_mp_max_used) ? Z->used : esp_mp_max_used;
#endif
ESP_LOGV(TAG, "Return esp_mp_exptmod %d", ret);
return ret;
}
#endif
#endif
#endif
#if defined(WOLFSSL_ESP32_CRYPT_RSA_PRI) && defined(WOLFSSL_HW_METRICS)
int esp_hw_show_mp_metrics(void)
{
int ret;
#if !defined(NO_ESP32_CRYPT) && defined(HW_MATH_ENABLED)
ret = MP_OKAY;
#if defined(NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL)
ESP_LOGI(TAG, "esp_mp_mul HW disabled with "
"NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL");
#else
ESP_LOGI(TAG, WOLFSSL_ESPIDF_BLANKLINE_MESSAGE);
ESP_LOGI(TAG, "esp_mp_mul HW acceleration enabled.");
ESP_LOGI(TAG, "Number of calls to esp_mp_mul: %lu",
esp_mp_mul_usage_ct);
ESP_LOGI(TAG, "Number of calls to esp_mp_mul with tiny operands: %lu",
esp_mp_mul_tiny_ct);
ESP_LOGI(TAG, "Number of calls to esp_mp_mul HW operand exceeded: %lu",
esp_mp_mul_max_exceeded_ct);
if (esp_mp_mul_error_ct == 0) {
ESP_LOGI(TAG, "Success: no esp_mp_mul() errors.");
}
else {
ESP_LOGW(TAG, "Number of esp_mp_mul failures: %lu",
esp_mp_mul_error_ct);
ret = MP_VAL;
}
#endif
#if defined(NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD)
ESP_LOGI(TAG, "esp_mp_mulmod HW disabled with "
"NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD");
#else
ESP_LOGI(TAG, WOLFSSL_ESPIDF_BLANKLINE_MESSAGE);
ESP_LOGI(TAG, "esp_mp_mulmod HW acceleration enabled.");
ESP_LOGI(TAG, "Number of calls to esp_mp_mulmod: %lu",
esp_mp_mulmod_usage_ct);
ESP_LOGI(TAG, "Number of calls to esp_mp_mulmod HW operand exceeded: %lu",
esp_mp_mulmod_max_exceeded_ct);
ESP_LOGI(TAG, "Number of fallback to SW mp_mulmod: %lu",
esp_mp_mulmod_fallback_ct);
if (esp_mp_mulmod_error_ct == 0) {
ESP_LOGI(TAG, "Success: no esp_mp_mulmod errors.");
}
else {
ESP_LOGW(TAG, "Number of esp_mp_mulmod failures: %lu",
esp_mp_mulmod_error_ct);
ret = MP_VAL;
}
if (esp_mp_mulmod_even_mod_ct == 0) {
ESP_LOGI(TAG, "Success: no esp_mp_mulmod even mod.");
}
else {
ESP_LOGW(TAG, "Number of esp_mp_mulmod even mod: %lu",
esp_mp_mulmod_even_mod_ct);
}
if (esp_mp_mulmod_error_ct == 0) {
ESP_LOGI(TAG, "Success: no esp_mp_mulmod small x or y.");
}
else {
ESP_LOGW(TAG, "Number of esp_mp_mulmod small x: %lu",
esp_mp_mulmod_small_x_ct);
ESP_LOGW(TAG, "Number of esp_mp_mulmod small y: %lu",
esp_mp_mulmod_small_y_ct);
}
#endif
#if defined(NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD)
ESP_LOGI(TAG, "esp_mp_exptmod HW disabled with "
"NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD");
#else
ESP_LOGI(TAG, WOLFSSL_ESPIDF_BLANKLINE_MESSAGE);
ESP_LOGI(TAG, "Number of calls to esp_mp_exptmod: %lu",
esp_mp_exptmod_usage_ct);
ESP_LOGI(TAG, "Number of calls to esp_mp_exptmod HW operand exceeded: %lu",
esp_mp_exptmod_max_exceeded_ct);
ESP_LOGI(TAG, "Number of fallback to SW mp_exptmod: %lu",
esp_mp_exptmod_fallback_ct);
if (esp_mp_exptmod_error_ct == 0) {
ESP_LOGI(TAG, "Success: no esp_mp_exptmod errors.");
}
else {
ESP_LOGW(TAG, "Number of esp_mp_exptmod errors: %lu",
esp_mp_exptmod_error_ct);
ret = MP_VAL;
}
#endif
ESP_LOGI(TAG, "Max N->used: esp_mp_max_used = %lu", esp_mp_max_used);
ESP_LOGI(TAG, "Max hw wait timeout: esp_mp_max_wait_timeout = %lu",
esp_mp_max_wait_timeout);
ESP_LOGI(TAG, "Max calc timeout: esp_mp_max_timeout = 0x%08lx",
esp_mp_max_timeout);
#else
ret = ESP_OK;
#endif
return ret;
}
#endif
#endif