fix(bignum): make constant-time prime sieve opt-in via config macro

mbedtls 4.1.1 replaced the trial-division small-factor test in prime
generation with a constant-time GCD against the 1380-bit small-primes
product (same change as upstream mbedtls commit 7a29052238 in 3.6.7).
The GCD runs a fixed (A_limbs + N_limbs) * biL iterations per prime
candidate, making RSA key generation ~5x slower on 64-bit hosts and
~10x slower on ESP chips, and its non-yielding software loop starves
the FreeRTOS idle task, tripping the task watchdog.

Restore the pre-3.6.7 variable-time trial division and keep the
constant-time implementation available behind the new
MBEDTLS_MPI_PRIME_SIEVE_VARIABLE_TIME macro (defined by ESP-IDF's
esp_config.h unless CONFIG_MBEDTLS_CONSTANT_TIME_PRIME_GEN is enabled).
The trial-division path keeps the 4.x input contract (X <= 997 returns
MBEDTLS_ERR_MPI_BAD_INPUT_DATA). Builds without the macro keep upstream
behavior unchanged.
This commit is contained in:
Ashish Sharma
2026-07-14 17:05:33 +08:00
parent 2d4f371046
commit ce3f3485a1
@@ -2085,6 +2085,90 @@ int mbedtls_mpi_inv_mod(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi
* value of nbits.
*/
static const mbedtls_mpi_sint small_primes_limit = 997;
#if defined(MBEDTLS_MPI_PRIME_SIEVE_VARIABLE_TIME)
/* Use the variable-time trial-division small-factor test from mbedtls 3.6.6
* instead of the constant-time GCD against the small-primes product.
*
* The constant-time GCD always runs (A_limbs + N_limbs) * biL iterations of
* full-width limb operations and is executed for every prime candidate
* (hundreds per generated prime), making RSA key generation an order of
* magnitude slower on 32-bit MCUs. It also runs entirely in software, so on
* targets where modular exponentiation is offloaded to hardware the CPU is
* kept busy for seconds without yielding, starving the idle task.
*
* The timing side channel closed upstream (variable-latency division leaking
* candidate-dependent information) requires an attacker able to observe the
* timing of individual operations during key generation, which is outside
* the threat model of devices that run no untrusted co-resident code.
*/
/* Gaps between primes, starting at 3. https://oeis.org/A001223 */
static const unsigned char small_prime_gaps[] = {
2, 2, 4, 2, 4, 2, 4, 6,
2, 6, 4, 2, 4, 6, 6, 2,
6, 4, 2, 6, 4, 6, 8, 4,
2, 4, 2, 4, 14, 4, 6, 2,
10, 2, 6, 6, 4, 6, 6, 2,
10, 2, 4, 2, 12, 12, 4, 2,
4, 6, 2, 10, 6, 6, 6, 2,
6, 4, 2, 10, 14, 4, 2, 4,
14, 6, 10, 2, 4, 6, 8, 6,
6, 4, 6, 8, 4, 8, 10, 2,
10, 2, 6, 4, 6, 8, 4, 2,
4, 12, 8, 4, 8, 4, 6, 12,
2, 18, 6, 10, 6, 6, 2, 6,
10, 6, 6, 2, 6, 6, 4, 2,
12, 10, 2, 4, 6, 6, 2, 12,
4, 6, 8, 10, 8, 10, 8, 6,
6, 4, 8, 6, 4, 8, 4, 14,
10, 12, 2, 10, 2, 4, 2, 10,
14, 4, 2, 4, 14, 4, 2, 4,
20, 4, 8, 10, 8, 4, 6, 6,
14, 4, 6, 6, 8, 6, /*reaches 997*/
0 /* the last entry is effectively unused */
};
/*
* Small divisors test (X must be positive)
*
* Return values:
* 0: no small factor (possible prime, more tests needed)
* MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime
* MBEDTLS_ERR_MPI_BAD_INPUT_DATA: input too small
* other negative: error
*/
static int mpi_check_small_factors(const mbedtls_mpi *X)
{
int ret = 0;
size_t i;
mbedtls_mpi_uint r;
unsigned p = 3; /* The first odd prime */
/* Same input contract as the constant-time implementation below:
* inputs no larger than the largest tested prime are rejected. */
if (mbedtls_mpi_cmp_int(X, small_primes_limit) <= 0) {
return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
}
if ((X->p[0] & 1) == 0) {
return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
}
/* X > small_primes_limit, so any zero remainder proves X composite. */
for (i = 0; i < sizeof(small_prime_gaps); p += small_prime_gaps[i], i++) {
MBEDTLS_MPI_CHK(mbedtls_mpi_mod_int(&r, X, p));
if (r == 0) {
return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
}
}
cleanup:
return ret;
}
#else /* MBEDTLS_MPI_PRIME_SIEVE_VARIABLE_TIME */
/* Product of small primes up to small_primes_limit included */
static const mbedtls_mpi_uint small_primes_product_limbs[] = {
MBEDTLS_BYTES_TO_T_UINT_8(0x4b, 0x13, 0x6a, 0x97, 0xbb, 0xd0, 0xdf, 0x95),
@@ -2161,6 +2245,8 @@ cleanup:
return ret;
}
#endif /* MBEDTLS_MPI_PRIME_SIEVE_VARIABLE_TIME */
/*
* Miller-Rabin pseudo-primality test (HAC 4.24)
*/