From 0d638e42bad9236ba8e3841bcb3fb9e16b89eccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 15 Apr 2026 10:47:47 +0200 Subject: [PATCH] ecp: pass over mbedtls_ecp_mod_p255_raw() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The test `if (X_Limbs > P255_WIDTH)` was useless: we know that X_limbs = 2 * P255_WIDTH. The implementation already had an explicit argument why the result is in range at the end. Signed-off-by: Manuel Pégourié-Gonnard --- library/ecp_curves.c | 26 ++++++++++++++++---------- library/ecp_invasive.h | 2 ++ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/library/ecp_curves.c b/library/ecp_curves.c index 25e9c5c390..8303d8a49b 100644 --- a/library/ecp_curves.c +++ b/library/ecp_curves.c @@ -5433,7 +5433,6 @@ int mbedtls_ecp_mod_p521_raw(mbedtls_mpi_uint *X, size_t X_limbs) /* * Fast quasi-reduction modulo p255 = 2^255 - 19 - * Write N as A0 + 2^256 A1, return A0 + 38 * A1 */ static int ecp_mod_p255(mbedtls_mpi *N) { @@ -5445,6 +5444,14 @@ cleanup: return ret; } +/* + * Raw fast quasi-reduction modulo p255 = 2^255 - 19 + * + * See ecp_invasive.h and FAST_QUASI_REDUCTION above. + * + * First write N as A0 + 2^256 A1, compute A0 + 38 * A1. + * Then handle the carry and remaining bit. + */ MBEDTLS_STATIC_TESTABLE int mbedtls_ecp_mod_p255_raw(mbedtls_mpi_uint *X, size_t X_Limbs) { @@ -5456,16 +5463,15 @@ int mbedtls_ecp_mod_p255_raw(mbedtls_mpi_uint *X, size_t X_Limbs) mbedtls_mpi_uint carry[P255_WIDTH] = { 0 }; /* Step 1: Reduction to P255_WIDTH limbs */ - if (X_Limbs > P255_WIDTH) { - /* Helper references for top part of X */ - mbedtls_mpi_uint * const A1 = X + P255_WIDTH; - const size_t A1_limbs = X_Limbs - P255_WIDTH; + mbedtls_mpi_uint * const A1 = X + P255_WIDTH; + const size_t A1_limbs = X_Limbs - P255_WIDTH; - /* X = A0 + 38 * A1, capture carry out */ - *carry = mbedtls_mpi_core_mla(X, P255_WIDTH, A1, A1_limbs, 38); - /* Clear top part */ - memset(A1, 0, sizeof(mbedtls_mpi_uint) * A1_limbs); - } + /* X = A0 + 38 * A1, capture carry out + * Note: X truncated to P255_WIDTH does not overlap with A1 + * (mbedtls_mpi_core_mla() doesn't support overlap other than aliasing) */ + *carry = mbedtls_mpi_core_mla(X, P255_WIDTH, A1, A1_limbs, 38); + /* Clear top part */ + memset(A1, 0, sizeof(mbedtls_mpi_uint) * A1_limbs); /* Step 2: Reduce to <2p * Split as A0 + 2^255*c, with c a scalar, and compute A0 + 19*c */ diff --git a/library/ecp_invasive.h b/library/ecp_invasive.h index c0b8f8f50b..15ecb094cb 100644 --- a/library/ecp_invasive.h +++ b/library/ecp_invasive.h @@ -244,6 +244,8 @@ int mbedtls_ecp_mod_p256k1_raw(mbedtls_mpi_uint *X, size_t X_limbs); * (double the bitlength of the modulus). * Upon return holds the reduced value which is * in range `0 <= X < 2 * N` (where N is the modulus). + * The bitlength of the reduced value is at most 256 + * (that is, 1 more than that of the modulus). * \param[in] X_limbs The length of \p X in limbs. * * \return \c 0 on success.