diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h index af1c50484f..c8d63d6038 100644 --- a/include/mbedtls/ecp.h +++ b/include/mbedtls/ecp.h @@ -218,17 +218,6 @@ mbedtls_ecp_point; * non-zero limbs than P, so that it may be efficiently brought into the range * [0, P) by a single constant-time conditional subtraction. * It must return 0 on success and non-zero on failure. - * - * \note Alternative implementations of the ECP module must obey the - * following constraints. - * * Group IDs must be distinct: if two group structures have - * the same ID, then they must be identical. - * * The fields \c id, \c P, \c A, \c B, \c G, \c N, - * \c pbits and \c nbits must have the same type and semantics - * as in the built-in implementation. - * They must be available for reading, but direct modification - * of these fields does not need to be supported. - * They do not need to be at the same offset in the structure. */ typedef struct mbedtls_ecp_group { mbedtls_ecp_group_id id; /*!< An internal group identifier. */ diff --git a/library/ecp_curves.c b/library/ecp_curves.c index d5b6be28b2..7e219954e0 100644 --- a/library/ecp_curves.c +++ b/library/ecp_curves.c @@ -14,8 +14,6 @@ #include "mbedtls/platform_util.h" #include "mbedtls/error.h" -#include "mbedtls/platform.h" - #include "constant_time_internal.h" #include "bn_mul.h" @@ -49,7 +47,7 @@ defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) /* For these curves, we build the group parameters dynamically. */ #define ECP_LOAD_GROUP -static mbedtls_mpi_uint mpi_one[] = { 1 }; +static const mbedtls_mpi_uint mpi_one[] = { 1 }; #endif /* @@ -4511,9 +4509,7 @@ static inline void ecp_mpi_load(mbedtls_mpi *X, const mbedtls_mpi_uint *p, size_ */ static inline void ecp_mpi_set1(mbedtls_mpi *X) { - X->s = 1; - X->n = 1; - X->p = mpi_one; + ecp_mpi_load(X, mpi_one, sizeof(mbedtls_mpi_uint)); } /* @@ -4845,15 +4841,49 @@ int mbedtls_ecp_group_load(mbedtls_ecp_group *grp, mbedtls_ecp_group_id id) } } +/* + * FAST_QUASI_REDUCTION + * + * Fast quasi-reduction exploits the structure of the prime P to bring a number + * from the range [0, P^2) (the result of a multiplication) into a range such + * that a single constant-time conditional subtract is enough to get the result + * in the range [0, P) (see ecp_modp() in ecp.c). + * + * There is one function per prime, with a common contract: + * (a) the output is in [0, 2P) (so we need at most 1 subtraction); + * (b) it has no more limbs than P (required by new bignum functions). + * + * Note that for primes whose bit length is a multiple of biL (32 or 64), + * (b) implies (a); for other primes (p255, p521), (a) implies (b). + * + * The general strategy is that P is written as P = 2^n - R, + * where n is the bit length of P and R a constant (see below). + * Then modulo P we have 2^n = R. + * So, we write X = X1 * 2^n + X0, and modulo P we have X = X0 + X1 * R. + * This can be used repeatedly to bring X to the desired range. + * + * This is only efficient if R was well chosen. There are two cases: + * 1. R is a small constant: + * - for secp521r1 it's actually 1: P = 2^521 - 1 + * - for secp256k1 it's a 33-bit number + * - for curve25519 it's 19: P = 2^255 - 19 (hence the name) + * 2. R is a sum of +/-1 * powers of 2^32: + * - for secp256r1, P = 2^256 - 2^224 + 2^192 + 2^96 - 1 + * - for secp384r1, P = 2^384 - 2^128 - 2^96 + 2^32 - 1 + * - for curve448, P = 2^448 - 2^224 - 1 + * + * The details vary for each prime, see the comments in each function. + */ + #if defined(MBEDTLS_ECP_NIST_OPTIM) /* - * Fast reduction modulo the primes used by the NIST curves. + * NIST_QUASI_REDUCTION * - * These functions are critical for speed, but not needed for correct - * operations. So, we make the choice to heavily rely on the internals of our - * bignum library, which creates a tight coupling between these functions and - * our MPI implementation. However, the coupling between the ECP module and - * MPI remains loose, since these functions can be deactivated at will. + * Compared to the way things are presented in FIPS 186-3 D.2, + * we proceed in columns, from right (least significant chunk) to left, + * adding chunks to N in place, and keeping a carry for the next chunk. + * This avoids moving things around in memory, and uselessly adding zeros, + * compared to the more straightforward, line-oriented approach. */ #if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) @@ -4900,7 +4930,7 @@ static inline void carry64(mbedtls_mpi_uint *dst, mbedtls_mpi_uint *carry) #define ADD_LAST add64(p, last_carry, &c) /* - * Fast quasi-reduction modulo p192 (FIPS 186-3 D.2.1) + * Fast quasi-reduction modulo p192 */ static int ecp_mod_p192(mbedtls_mpi *N) { @@ -4913,6 +4943,12 @@ cleanup: return ret; } +/* + * Raw fast quasi-reduction modulo p192 + * + * See ecp_invasive.h and FAST_QUASI_REDUCTION above, + * plus NIST_QUASI_REDUCTION above and FIPS 186-3 D.2.1. + */ MBEDTLS_STATIC_TESTABLE int mbedtls_ecp_mod_p192_raw(mbedtls_mpi_uint *Np, size_t Nn) { @@ -4929,24 +4965,21 @@ int mbedtls_ecp_mod_p192_raw(mbedtls_mpi_uint *Np, size_t Nn) ADD(3); ADD(5); NEXT; // A0 += A3 + A5 ADD(3); ADD(4); ADD(5); NEXT; // A1 += A3 + A4 + A5 ADD(4); ADD(5); // A2 += A4 + A5 + /* Similarly to mbedtls_ecp_mod_p256_raw(), we have 0 <= c <= 3. */ - RESET; - - /* Use the reduction for the carry as well: - * 2^192 * last_carry = 2^64 * last_carry + last_carry mod P192 - * It can generate a carry. */ - ADD_LAST; NEXT; // A0 += last_carry - ADD_LAST; NEXT; // A1 += last_carry - // A2 += carry - - RESET; - - /* Use the reduction for the carry as well: - * 2^192 * last_carry = 2^64 * last_carry + last_carry mod P192 + /* The reduced value is 2^192 * c + X0, with X0 the low 3 chunks of X. + * Set R = 2^64 + 1, and update with X_new = X0 + c * R. + * + * The rest of the reasoning is similar to mbedtls_ecp_mod_p256_raw(), + * and we see that two rounds are enough to bring the result in range. */ - ADD_LAST; NEXT; // A0 += last_carry - ADD_LAST; NEXT; // A1 += last_carry - // A2 += carry + for (size_t round = 0; round < 2; ++round) { + RESET; + + ADD_LAST; NEXT; // A0 += last_carry + ADD_LAST; NEXT; // A1 += last_carry + // A2 += carry + } LAST; @@ -4965,13 +4998,6 @@ int mbedtls_ecp_mod_p192_raw(mbedtls_mpi_uint *Np, size_t Nn) #if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) || \ defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) - -/* - * The reader is advised to first understand ecp_mod_p192() since the same - * general structure is used here, but with additional complications: - * (1) chunks of 32 bits, and (2) subtractions. - */ - /* * For these primes, we need to handle data in chunks of 32 bits. * This makes it more complicated if we use 64 bits limbs in MPI, @@ -5069,7 +5095,7 @@ static inline int8_t extract_carry(int64_t cur) #if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) /* - * Fast quasi-reduction modulo p224 (FIPS 186-3 D.2.2) + * Fast quasi-reduction modulo p224 */ static int ecp_mod_p224(mbedtls_mpi *N) { @@ -5081,6 +5107,12 @@ cleanup: return ret; } +/* + * Raw fast quasi-reduction modulo p224 + * + * See ecp_invasive.h and FAST_QUASI_REDUCTION above, + * plus NIST_QUASI_REDUCTION above and FIPS 186-3 D.2.2. + */ MBEDTLS_STATIC_TESTABLE int mbedtls_ecp_mod_p224_raw(mbedtls_mpi_uint *X, size_t X_limbs) { @@ -5122,7 +5154,7 @@ int mbedtls_ecp_mod_p224_raw(mbedtls_mpi_uint *X, size_t X_limbs) #if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) /* - * Fast quasi-reduction modulo p256 (FIPS 186-3 D.2.3) + * Fast quasi-reduction modulo p256 */ static int ecp_mod_p256(mbedtls_mpi *N) { @@ -5134,6 +5166,12 @@ cleanup: return ret; } +/* + * Raw fast quasi-reduction modulo p256 + * + * See ecp_invasive.h and FAST_QUASI_REDUCTION above, + * plus NIST_QUASI_REDUCTION above and FIPS 186-3 D.2.3. + */ MBEDTLS_STATIC_TESTABLE int mbedtls_ecp_mod_p256_raw(mbedtls_mpi_uint *X, size_t X_limbs) { @@ -5166,32 +5204,52 @@ int mbedtls_ecp_mod_p256_raw(mbedtls_mpi_uint *X, size_t X_limbs) ADD(15); ADD(15); ADD(15); ADD(8); SUB(10); SUB(11); SUB(12); SUB(13); // A7 + /* The carry is easily seen to be in the range -5 <= c <= +5, + * because on the top chunk we do 4 explicit add (resp. sub), plus one + * implicit (adding the carry from the previous limbs), and each can + * increment (resp. decrement) the carry. + * Tighter estimates can probably be obtained, but we don't need them. */ - RESET; + /* From now on, the reduced value is 2^256 * c + X0, + * where X0 is A0 + 2^32 * A1 + ... + 2^224 * A7 (the low 8 chunks of X). + * Note that c may be negative, but X0 is always in [0, 2^256). + * + * Set R = 2^224 - 2^192 - 2^96 + 1 and use 2^256 = R (mod p256), + * so the update formula is X = X0 + c * R. + * + * Let's call X_ori the value before the loop, + * X_1st the value after the first iteration, + * X_2nd the value after the second iteration. + * + * First round: + * We have 0 <= X_ori < 2^256 and -8 < -5 <= last_c <= 5 < 8, + * so -2^227 < last_c * R < 2^227 + * and -2^227 < X_1st < 2^256 + 2^227. + * Again X_1st is represented as 2^256 * c + X0, but now c is -1, 0 or 1. + * + * Second round: + * - If c is 0, then X_2nd = X0 + 0 * R = X0 which is in range. + * - If c is 1, then X_2nd = X0 + 1 * R is clearly non-negative. + * Also, since X_1st < 2^256 + 2^227, we have X0 < 2^227, + * so X_2nd = X0 + 1 * R < 2^227 + 2^224 < 2^256. + * - If c is -1 then X_2nd = X0 - 1 * R is clearly < 2^256. + * Also, since X_1st > -2^227 and X_1st = - 2^256 + X0, + * we have X0 > 2^256 - 2^227 + * so X_2nd = X0 - 1 * R > 2^256 - 2^227 - 2^224 >= 0. + * In all cases, 0 <= X_2nd < 2^256 as desired. + */ + for (size_t round = 0; round < 2; ++round) { + RESET; - /* Use 2^224 * (2^32 - 1) + 2^192 + 2^96 - 1 - * to modulo reduce the final carry. */ - ADD_LAST; NEXT; // A0 - ; NEXT; // A1 - ; NEXT; // A2 - SUB_LAST; NEXT; // A3 - ; NEXT; // A4 - ; NEXT; // A5 - SUB_LAST; NEXT; // A6 - ADD_LAST; // A7 - - RESET; - - /* Use 2^224 * (2^32 - 1) + 2^192 + 2^96 - 1 - * to modulo reduce the carry generated by the previous reduction. */ - ADD_LAST; NEXT; // A0 - ; NEXT; // A1 - ; NEXT; // A2 - SUB_LAST; NEXT; // A3 - ; NEXT; // A4 - ; NEXT; // A5 - SUB_LAST; NEXT; // A6 - ADD_LAST; // A7 + ADD_LAST; NEXT; // A0 + ; NEXT; // A1 + ; NEXT; // A2 + SUB_LAST; NEXT; // A3 + ; NEXT; // A4 + ; NEXT; // A5 + SUB_LAST; NEXT; // A6 + ADD_LAST; // A7 + } LAST; @@ -5202,7 +5260,7 @@ int mbedtls_ecp_mod_p256_raw(mbedtls_mpi_uint *X, size_t X_limbs) #if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) /* - * Fast quasi-reduction modulo p384 (FIPS 186-3 D.2.4) + * Fast quasi-reduction modulo p384 */ static int ecp_mod_p384(mbedtls_mpi *N) { @@ -5214,6 +5272,12 @@ cleanup: return ret; } +/* + * Raw fast quasi-reduction modulo p384 + * + * See ecp_invasive.h and FAST_QUASI_REDUCTION above, + * plus NIST_QUASI_REDUCTION above and FIPS 186-3 D.2.4. + */ MBEDTLS_STATIC_TESTABLE int mbedtls_ecp_mod_p384_raw(mbedtls_mpi_uint *X, size_t X_limbs) { @@ -5258,37 +5322,30 @@ int mbedtls_ecp_mod_p384_raw(mbedtls_mpi_uint *X, size_t X_limbs) ADD(23); ADD(20); ADD(19); SUB(22); // A11 + /* Similarly to mbedtls_ecp_mod_p256_raw(), we have -2 <= c <= 4. */ - RESET; + /* The reduced value is 2^384 * c + X0, with X0 the low 12 chunks of X. + * Set R = 2^128 + 2^96 - 2^32 + 1, and update with X_new = X0 + c * R. + * + * The rest of the reasoning is similar to mbedtls_ecp_mod_p256_raw(), + * and we see that two rounds are enough to bring the result in range. + */ + for (size_t round = 0; round < 2; ++round) { + RESET; - /* Use 2^384 = P + 2^128 + 2^96 - 2^32 + 1 to modulo reduce the final carry */ - ADD_LAST; NEXT; // A0 - SUB_LAST; NEXT; // A1 - ; NEXT; // A2 - ADD_LAST; NEXT; // A3 - ADD_LAST; NEXT; // A4 - ; NEXT; // A5 - ; NEXT; // A6 - ; NEXT; // A7 - ; NEXT; // A8 - ; NEXT; // A9 - ; NEXT; // A10 - // A11 - - RESET; - - ADD_LAST; NEXT; // A0 - SUB_LAST; NEXT; // A1 - ; NEXT; // A2 - ADD_LAST; NEXT; // A3 - ADD_LAST; NEXT; // A4 - ; NEXT; // A5 - ; NEXT; // A6 - ; NEXT; // A7 - ; NEXT; // A8 - ; NEXT; // A9 - ; NEXT; // A10 + ADD_LAST; NEXT; // A0 + SUB_LAST; NEXT; // A1 + ; NEXT; // A2 + ADD_LAST; NEXT; // A3 + ADD_LAST; NEXT; // A4 + ; NEXT; // A5 + ; NEXT; // A6 + ; NEXT; // A7 + ; NEXT; // A8 + ; NEXT; // A9 + ; NEXT; // A10 // A11 + } LAST; @@ -5318,13 +5375,13 @@ int mbedtls_ecp_mod_p384_raw(mbedtls_mpi_uint *X, size_t X_limbs) #if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) /* Size of p521 in terms of mbedtls_mpi_uint */ -#define P521_WIDTH (521 / 8 / sizeof(mbedtls_mpi_uint) + 1) +#define P521_WIDTH BITS_TO_LIMBS(521) /* Bits to keep in the most significant mbedtls_mpi_uint */ #define P521_MASK 0x01FF /* - * Fast quasi-reduction modulo p521 = 2^521 - 1 (FIPS 186-3 D.2.5) + * Fast quasi-reduction modulo p521 */ static int ecp_mod_p521(mbedtls_mpi *N) { @@ -5336,6 +5393,14 @@ cleanup: return ret; } +/* + * Raw fast quasi-reduction modulo p521 = 2^521 - 1 + * + * See ecp_invasive.h and FAST_QUASI_REDUCTION above. + * + * First handle whole limbs above 521 bits, + * then handle the carry as well as remaining bits in the top limb. + */ MBEDTLS_STATIC_TESTABLE int mbedtls_ecp_mod_p521_raw(mbedtls_mpi_uint *X, size_t X_limbs) { @@ -5346,21 +5411,21 @@ int mbedtls_ecp_mod_p521_raw(mbedtls_mpi_uint *X, size_t X_limbs) } /* Step 1: Reduction to P521_WIDTH limbs */ - /* Helper references for bottom part of X */ + /* Pointers to bottom/top part of X - note that they don't overlap, + * as required for the call to mbedtls_mpi_core_mla() below. */ mbedtls_mpi_uint *X0 = X; size_t X0_limbs = P521_WIDTH; - /* Helper references for top part of X */ mbedtls_mpi_uint *X1 = X + X0_limbs; size_t X1_limbs = X_limbs - X0_limbs; - /* Split X as X0 + 2^P521_WIDTH X1 and compute X0 + 2^(biL - 9) X1. - * (We are using that 2^P521_WIDTH = 2^(512 + biL) and that + /* Split X as X0 + 2^(P521_WIDTH * biL) X1 and compute X0 + 2^(biL - 9) X1. + * (We are using that 2^(P521_WIDTH * biL) = 2^(512 + biL) and that * 2^(512 + biL) X1 = 2^(biL - 9) X1 mod P521.) * The high order limb of the result will be held in carry and the rest * in X0 (that is the result will be represented as - * 2^P521_WIDTH carry + X0). + * 2^(P521_WIDTH * biL) * carry + X0). * * Also, note that the resulting carry is either 0 or 1: - * X0 < 2^P521_WIDTH = 2^(512 + biL) and X1 < 2^(P521_WIDTH-biL) = 2^512 + * X0 < 2^(512 + biL) and X1 < 2^512 * therefore * X0 + 2^(biL - 9) X1 < 2^(512 + biL) + 2^(512 + biL - 9) * which in turn is less than 2 * 2^(512 + biL). @@ -5375,7 +5440,7 @@ int mbedtls_ecp_mod_p521_raw(mbedtls_mpi_uint *X, size_t X_limbs) * At this point X is reduced to P521_WIDTH limbs. What remains is to add * the carry (that is 2^P521_WIDTH carry) and to reduce mod P521. */ - /* 2^P521_WIDTH carry = 2^(512 + biL) carry = 2^(biL - 9) carry mod P521. + /* 2^(P521_WIDTH * biL) * carry = 2^(512 + biL) carry = 2^(biL - 9) carry mod P521. * Also, recall that carry is either 0 or 1. */ mbedtls_mpi_uint addend = carry << (biL - 9); /* Keep the top 9 bits and reduce the rest, using 2^521 = 1 mod P521. */ @@ -5406,11 +5471,10 @@ int mbedtls_ecp_mod_p521_raw(mbedtls_mpi_uint *X, size_t X_limbs) #if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) /* Size of p255 in terms of mbedtls_mpi_uint */ -#define P255_WIDTH (255 / 8 / sizeof(mbedtls_mpi_uint) + 1) +#define P255_WIDTH BITS_TO_LIMBS(255) /* * 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) { @@ -5422,6 +5486,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) { @@ -5430,22 +5502,18 @@ int mbedtls_ecp_mod_p255_raw(mbedtls_mpi_uint *X, size_t X_Limbs) return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; } - mbedtls_mpi_uint *carry = mbedtls_calloc(P255_WIDTH, ciL); - if (carry == NULL) { - return MBEDTLS_ERR_ECP_ALLOC_FAILED; - } + 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 */ @@ -5464,7 +5532,6 @@ int mbedtls_ecp_mod_p255_raw(mbedtls_mpi_uint *X, size_t X_Limbs) * - If X > 2^255 ==> X < 2^256 - 2^255 < 2p */ (void) mbedtls_mpi_core_add(X, X, carry, P255_WIDTH); - mbedtls_free(carry); return 0; } #endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ @@ -5472,15 +5539,21 @@ int mbedtls_ecp_mod_p255_raw(mbedtls_mpi_uint *X, size_t X_Limbs) #if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) /* Size of p448 in terms of mbedtls_mpi_uint */ -#define P448_WIDTH (448 / 8 / sizeof(mbedtls_mpi_uint)) +#define P448_WIDTH BITS_TO_LIMBS(448) -/* Number of limbs fully occupied by 2^224 (max), and limbs used by it (min) */ -#define DIV_ROUND_UP(X, Y) (((X) + (Y) -1) / (Y)) +/* Number of bytes for a 224-bit value */ #define P224_SIZE (224 / 8) -#define P224_WIDTH_MIN (P224_SIZE / sizeof(mbedtls_mpi_uint)) -#define P224_WIDTH_MAX DIV_ROUND_UP(P224_SIZE, sizeof(mbedtls_mpi_uint)) -#define P224_UNUSED_BITS ((P224_WIDTH_MAX * sizeof(mbedtls_mpi_uint) * 8) - 224) +/* Number of limbs fully used to store a 224-bit value */ +#define P224_WIDTH_MIN (P224_SIZE / sizeof(mbedtls_mpi_uint)) +/* Number or limbs partially used to store a 224-bit value. + * With 32-bit limbs we have MAX == MIN, but with 64-bit limbs MAX == MIN + 1 */ +#define DIV_ROUND_UP(X, Y) (((X) + (Y) -1) / (Y)) +#define P224_WIDTH_MAX DIV_ROUND_UP(P224_SIZE, sizeof(mbedtls_mpi_uint)) + +/* + * Fast quasi-reduction module p448 + */ static int ecp_mod_p448(mbedtls_mpi *N) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; @@ -5523,12 +5596,36 @@ static void ecp_shift_l_224(mbedtls_mpi_uint *X) #endif } +/* In-place truncated to 224-bits: X %= 2^224 + * X must be P448_WIDTH + 1 limbs */ +static void ecp_trunc_224(mbedtls_mpi_uint *X) +{ +#if defined(MBEDTLS_HAVE_INT64) && defined(MBEDTLS_IS_BIG_ENDIAN) + /* Since 224 is only a multiple of 32 but not of 64, the 224-bit + * limit falls in the middle of a limb. Clear the top 32 bits of that limb, + * (that is, keep only its low 32 bits). Higher limbs can be fully cleared. + */ + X[P224_WIDTH_MIN] &= (mbedtls_mpi_uint) 0xffffffff; + memset(X + P224_WIDTH_MAX, 0, ((P448_WIDTH + 1 - P224_WIDTH_MAX) * ciL)); +#else + /* Shortcut for 32-bit and little-endian 64-bit. */ + memset((char *) X + P224_SIZE, 0, P224_SIZE + ciL); +#endif +} + /* - * Fast quasi-reduction modulo p448 = 2^448 - 2^224 - 1 - * Write X as A0 + 2^448 A1 and A1 as B0 + 2^224 B1, and return A0 + A1 + B1 + - * (B0 + B1) * 2^224. This is different to the reference implementation of + * Raw fast quasi-reduction modulo p448 = 2^448 - 2^224 - 1 + * + * See ecp_invasive.h and FAST_QUASI_REDUCTION above. + * + * Write X as A0 + 2^448 A1 and A1 as B0 + 2^224 B1, and + * compute A0 + A1 + B1 + (B0 + B1) * 2^224. + * + * This is different to the reference implementation of * Curve448, which uses its own special 56-bit limbs rather than a generic - * bignum library. We could squeeze some extra speed out on 32-bit machines by + * bignum library. + * + * We could squeeze some extra speed out on 32-bit machines by * splitting N up into 32-bit limbs and doing the arithmetic using the limbs * directly as we do for the NIST primes above, but for 64-bit targets it should * use half the number of operations if we do the reduction with 224-bit limbs, @@ -5537,106 +5634,78 @@ static void ecp_shift_l_224(mbedtls_mpi_uint *X) MBEDTLS_STATIC_TESTABLE int mbedtls_ecp_mod_p448_raw(mbedtls_mpi_uint *X, size_t X_limbs) { - size_t round; - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - if (X_limbs != BITS_TO_LIMBS(448) * 2) { return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; } /* Both M and Q require an extra limb to catch carries. */ - size_t M_limbs = BITS_TO_LIMBS(448) + 1; - - const size_t Q_limbs = M_limbs; - mbedtls_mpi_uint *M = NULL; - mbedtls_mpi_uint *Q = NULL; - - M = mbedtls_calloc(M_limbs, ciL); - - if (M == NULL) { - return MBEDTLS_ERR_ECP_ALLOC_FAILED; - } - - Q = mbedtls_calloc(Q_limbs, ciL); - - if (Q == NULL) { - ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; - goto cleanup; - } + mbedtls_mpi_uint M[P448_WIDTH + 1]; + mbedtls_mpi_uint Q[P448_WIDTH + 1]; /* M = A1 */ - memset(M, 0, (M_limbs * ciL)); - /* Do not copy into the overflow limb, as this would read past the end of - * X. */ - memcpy(M, X + P448_WIDTH, ((M_limbs - 1) * ciL)); + memcpy(M, X + P448_WIDTH, P448_WIDTH * ciL); + M[P448_WIDTH] = 0; /* X = A0 */ - memset(X + P448_WIDTH, 0, ((M_limbs - 1) * ciL)); + memset(X + P448_WIDTH, 0, P448_WIDTH * ciL); /* X = X + M = A0 + A1 */ - /* Carry here fits in oversize X. Oversize M means it will get - * added in, not returned as carry. */ - (void) mbedtls_mpi_core_add(X, X, M, M_limbs); + /* The result is at most 449 bits, so it fits in P448_WIDTH + 1 limbs. + * and we know the final carry returned by the function will be 0. */ + (void) mbedtls_mpi_core_add(X, X, M, P448_WIDTH + 1); /* Q = B1 = M >> 224 */ ecp_copy_shift_r_224(Q, M); - /* X = X + Q = (A0 + A1) + B1 - * Oversize Q catches potential carry here when X is already max 448 bits. - */ - (void) mbedtls_mpi_core_add(X, X, Q, Q_limbs); + /* X = X + Q = (A0 + A1) + B1 */ + /* Inputs are at most 449 bits and 224 bits, so the result fits. */ + (void) mbedtls_mpi_core_add(X, X, Q, P448_WIDTH + 1); /* M = B0 */ -#ifdef MBEDTLS_HAVE_INT64 - M[P224_WIDTH_MIN] &= ((mbedtls_mpi_uint)-1) >> (P224_UNUSED_BITS); - #endif - memset(M + P224_WIDTH_MAX, 0, ((M_limbs - P224_WIDTH_MAX) * ciL)); + ecp_trunc_224(M); /* M = M + Q = B0 + B1 */ - (void) mbedtls_mpi_core_add(M, M, Q, Q_limbs); + (void) mbedtls_mpi_core_add(M, M, Q, P448_WIDTH + 1); /* M = (B0 + B1) * 2^224 */ /* Shifted carry bit from the addition fits in oversize M. */ ecp_shift_l_224(M); /* X = X + M = (A0 + A1 + B1) + (B0 + B1) * 2^224 */ - (void) mbedtls_mpi_core_add(X, X, M, M_limbs); + (void) mbedtls_mpi_core_add(X, X, M, P448_WIDTH + 1); - /* In the second and third rounds A1 and B0 have at most 1 non-zero limb and - * B1=0. - * Using this we need to calculate: - * A0 + A1 + B1 + (B0 + B1) * 2^224 = A0 + A1 + B0 * 2^224. */ - for (round = 0; round < 2; ++round) { + /* Clear M once before the loop */ + memset(M, 0, ((P448_WIDTH + 1) * ciL)); - /* M = A1 */ - memset(M, 0, (M_limbs * ciL)); - memcpy(M, X + P448_WIDTH, ((M_limbs - 1) * ciL)); + /* Now X < 2^448 + 2^448 + 2^224 + (2^224 + 2^224) * 2^224, + * so X is at most 451 bits. So, in subsequent rounds, + * A1 has at most 1 non-zero limb, so B0 = A1 and B1 = 0. + * So the update formula simplifies as follows: + * A0 + A1 + B1 + (B0 + B1) * 2^224 = A0 + A1 + A1 * 2^224. + * + * Two rounds are enough because: + * 1st round: A0 < 2^448, A1 <= 2^3 - 1 + * so X < 2^448 + 2^227 (at most 449 bits). + * 2nd round: Either A1 is 0 and we're done already, + * or A1 is 1 and A0 = X - A1 * 2^448 < 2^227, + * so X < 2^227 + 1 + 1 * 2^224 is less than 448 bits. + */ + for (size_t round = 0; round < 2; ++round) { + /* M = A1 + A1 * 2^224 + * Since A1 is only a few bits, we can directly write A1 << 224 to the + * right place (which might not be on a limb boundary). + * (Note: other limbs of M were cleared before the loop.) */ + M[0] = X[P448_WIDTH]; + M[224 / biL] = X[P448_WIDTH] << (224 % biL); - /* X = A0 */ - memset(X + P448_WIDTH, 0, ((M_limbs - 1) * ciL)); + /* X = A0 (only 1 limb to clear) */ + X[P448_WIDTH] = 0; - /* M = A1 + B0 * 2^224 - * We know that only one limb of A1 will be non-zero and that it will be - * limb 0. We also know that B0 is the bottom 224 bits of A1 (which is - * then shifted up 224 bits), so, given M is currently A1 this turns - * into: - * M = M + (M << 224) - * As the single non-zero limb in B0 will be A1 limb 0 shifted up by 224 - * bits, we can just move that into the right place, shifted up - * accordingly.*/ - M[P224_WIDTH_MIN] = M[0] << (224 & (biL - 1)); - - /* X = A0 + (A1 + B0 * 2^224) */ - (void) mbedtls_mpi_core_add(X, X, M, M_limbs); + /* X = A0 + (A1 + A1 * 2^224) */ + (void) mbedtls_mpi_core_add(X, X, M, P448_WIDTH + 1); } - ret = 0; - -cleanup: - mbedtls_free(M); - mbedtls_free(Q); - - return ret; + return 0; } #endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */ @@ -5644,21 +5713,33 @@ cleanup: defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) || \ defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) -/* - * Fast quasi-reduction modulo P = 2^s - R, - * with R about 33 bits, used by the Koblitz curves. - * - * Write X as A0 + 2^224 A1, return A0 + R * A1. - */ -#define P_KOBLITZ_R (8 / sizeof(mbedtls_mpi_uint)) // Limbs in R +/* Limb size of R for ecp_mod_koblitz() */ +#define P_KOBLITZ_R BITS_TO_LIMBS(33) +/* Maximum limb size of P for ecp_mod_koblitz() */ +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +#define P_KOBLITZ_MAX_P BITS_TO_LIMBS(256) +#elif defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) +#define P_KOBLITZ_MAX_P BITS_TO_LIMBS(224) +#else +#define P_KOBLITZ_MAX_P BITS_TO_LIMBS(192) +#endif + +/* + * Fast quasi-reduction modulo P = 2^n - R, + * with R a curve-dependent 33-bit value. + * + * This function is the core of mbedtls_ecp_mod_p192k1_raw(), + * mbedtls_ecp_mod_p224k1_raw(), and mbedtls_ecp_mod_p256k1_raw(). + * + * See ecp_invasive.h and FAST_QUASI_REDUCTION above. + * + * Write X as A0 + 2^n A1, update as A0 + R * A1. + */ static inline int ecp_mod_koblitz(mbedtls_mpi_uint *X, - size_t X_limbs, mbedtls_mpi_uint *R, size_t bits) { - int ret = 0; - /* Determine if A1 is aligned to limb bitsize. If not then the used limbs * of P, A0 and A1 must be set accordingly and there is a middle limb * which is shared by A0 and A1 and need to handle accordingly. @@ -5667,29 +5748,18 @@ static inline int ecp_mod_koblitz(mbedtls_mpi_uint *X, size_t adjust = (shift + biL - 1) / biL; size_t P_limbs = bits / biL + adjust; - mbedtls_mpi_uint *A1 = mbedtls_calloc(P_limbs, ciL); - if (A1 == NULL) { - return MBEDTLS_ERR_ECP_ALLOC_FAILED; - } + mbedtls_mpi_uint A1[P_KOBLITZ_MAX_P] = { 0 }; /* Create a buffer to store the value of `R * A1` */ size_t R_limbs = P_KOBLITZ_R; - size_t M_limbs = P_limbs + R_limbs; - mbedtls_mpi_uint *M = mbedtls_calloc(M_limbs, ciL); - if (M == NULL) { - ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; - goto cleanup; - } + mbedtls_mpi_uint M[P_KOBLITZ_MAX_P + P_KOBLITZ_R] = { 0 }; mbedtls_mpi_uint mask = 0; if (adjust != 0) { mask = ((mbedtls_mpi_uint) 1 << shift) - 1; } - /* Two passes are needed to reduce the value of `A0 + R * A1` and then - * we need an additional one to reduce the possible overflow during - * the addition. - */ + /* See end of the loop for why 3 passes */ for (size_t pass = 0; pass < 3; pass++) { /* Copy A1 */ memcpy(A1, X + P_limbs - adjust, P_limbs * ciL); @@ -5704,30 +5774,28 @@ static inline int ecp_mod_koblitz(mbedtls_mpi_uint *X, X[P_limbs - 1] &= mask; } - /* X = A0 - * Zeroize the A1 part of X to keep only the A0 part. - */ - for (size_t i = P_limbs; i < X_limbs; i++) { - X[i] = 0; - } + /* X = A0: Zeroize the A1 part of X to keep only the A0 part. */ + memset(X + P_limbs, 0, P_limbs * ciL); /* X = A0 + R * A1 */ mbedtls_mpi_core_mul(M, A1, P_limbs, R, R_limbs); (void) mbedtls_mpi_core_add(X, X, M, P_limbs + R_limbs); - - /* Carry can not be generated since R is a 33-bit value and stored in - * 64 bits. The result value of the multiplication is at most - * P length + 33 bits in length and the result value of the addition - * is at most P length + 34 bits in length. So the result of the - * addition always fits in P length + 64 bits. + /* The above cannot generate a carry since P_limbs + R_limbs is enough. + * + * More precisely, if n is P's bit length: + * 1st pass: A0 is n bits, R * A1 is 33 + n, so X is n + 34 bits. + * This fits in P_limbs + R_limbs which is n + 64 bits. + * 2nd pass: A0 is n bits, R * A1 is 33 + 34, so X is n + 1 bits. + * Actually, X < 2^n + 2^67 + * 3rd pass: Either A1 is 0, then X = A0 is at most n bits. + * Or A1 is 1, but then A0 = X - A1 * 2^n < 2^67, + * so X = A0 + R * A1 < 2^67 + 2^33 is less than n bits, + * since n >= 68. + * So, after the 3rd pass, X is at most n bits. */ } -cleanup: - mbedtls_free(M); - mbedtls_free(A1); - - return ret; + return 0; } #endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED) || @@ -5737,8 +5805,7 @@ cleanup: #if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) /* - * Fast quasi-reduction modulo p192k1 = 2^192 - R, - * with R = 2^32 + 2^12 + 2^8 + 2^7 + 2^6 + 2^3 + 1 = 0x01000011C9 + * Fast quasi-reduction modulo p192k1 = 2^192 - 0x01000011C9 */ static int ecp_mod_p192k1(mbedtls_mpi *N) { @@ -5751,6 +5818,9 @@ cleanup: return ret; } +/* + * Raw fast quasi-reduction modulo p192k1 = 2^192 - 0x01000011C9 + */ MBEDTLS_STATIC_TESTABLE int mbedtls_ecp_mod_p192k1_raw(mbedtls_mpi_uint *X, size_t X_limbs) { @@ -5763,7 +5833,7 @@ int mbedtls_ecp_mod_p192k1_raw(mbedtls_mpi_uint *X, size_t X_limbs) return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; } - return ecp_mod_koblitz(X, X_limbs, Rp, 192); + return ecp_mod_koblitz(X, Rp, 192); } #endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ @@ -5771,8 +5841,7 @@ int mbedtls_ecp_mod_p192k1_raw(mbedtls_mpi_uint *X, size_t X_limbs) #if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) /* - * Fast quasi-reduction modulo p224k1 = 2^224 - R, - * with R = 2^32 + 2^12 + 2^11 + 2^9 + 2^7 + 2^4 + 2 + 1 = 0x0100001A93 + * Fast quasi-reduction modulo p224k1 = 2^224 - 0x0100001A93 */ static int ecp_mod_p224k1(mbedtls_mpi *N) { @@ -5785,6 +5854,9 @@ cleanup: return ret; } +/* + * Raw fast quasi-reduction modulo p224k1 = 2^224 - 0x0100001A93 + */ MBEDTLS_STATIC_TESTABLE int mbedtls_ecp_mod_p224k1_raw(mbedtls_mpi_uint *X, size_t X_limbs) { @@ -5797,7 +5869,7 @@ int mbedtls_ecp_mod_p224k1_raw(mbedtls_mpi_uint *X, size_t X_limbs) return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; } - return ecp_mod_koblitz(X, X_limbs, Rp, 224); + return ecp_mod_koblitz(X, Rp, 224); } #endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ @@ -5805,8 +5877,7 @@ int mbedtls_ecp_mod_p224k1_raw(mbedtls_mpi_uint *X, size_t X_limbs) #if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) /* - * Fast quasi-reduction modulo p256k1 = 2^256 - R, - * with R = 2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1 = 0x01000003D1 + * Fast quasi-reduction modulo p256k1 = 2^256 - 0x01000003D1 */ static int ecp_mod_p256k1(mbedtls_mpi *N) { @@ -5819,6 +5890,9 @@ cleanup: return ret; } +/* + * Raw fast quasi-reduction modulo p256k1 = 2^256 - 0x01000003D1 + */ MBEDTLS_STATIC_TESTABLE int mbedtls_ecp_mod_p256k1_raw(mbedtls_mpi_uint *X, size_t X_limbs) { @@ -5831,7 +5905,7 @@ int mbedtls_ecp_mod_p256k1_raw(mbedtls_mpi_uint *X, size_t X_limbs) return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; } - return ecp_mod_koblitz(X, X_limbs, Rp, 256); + return ecp_mod_koblitz(X, Rp, 256); } #endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ diff --git a/library/ecp_invasive.h b/library/ecp_invasive.h index 0388122ab3..faf28c5a34 100644 --- a/library/ecp_invasive.h +++ b/library/ecp_invasive.h @@ -61,7 +61,7 @@ int mbedtls_ecp_gen_privkey_mx(size_t high_bit, #if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) -/** Fast quasi-reduction modulo p192 (FIPS 186-3 D.2.1) +/** Fast quasi-reduction modulo p192 * * This operation expects a 384 bit MPI and the result of the reduction * is a 192 bit MPI. @@ -80,7 +80,7 @@ int mbedtls_ecp_mod_p192_raw(mbedtls_mpi_uint *Np, size_t Nn); #if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) -/** Fast quasi-reduction modulo p224 (FIPS 186-3 D.2.2) +/** Fast quasi-reduction modulo p224 * * \param[in,out] X The address of the MPI to be converted. * Must have exact limb size that stores a 448-bit MPI @@ -102,7 +102,7 @@ int mbedtls_ecp_mod_p224_raw(mbedtls_mpi_uint *X, size_t X_limbs); #if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) -/** Fast quasi-reduction modulo p256 (FIPS 186-3 D.2.3) +/** Fast quasi-reduction modulo p256 * * \param[in,out] X The address of the MPI to be converted. * Must have exact limb size that stores a 512-bit MPI @@ -124,7 +124,7 @@ int mbedtls_ecp_mod_p256_raw(mbedtls_mpi_uint *X, size_t X_limbs); #if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) -/** Fast quasi-reduction modulo p521 = 2^521 - 1 (FIPS 186-3 D.2.5) +/** Fast quasi-reduction modulo p521 = 2^521 - 1 * * \param[in,out] X The address of the MPI to be converted. * Must have twice as many limbs as the modulus @@ -146,7 +146,7 @@ int mbedtls_ecp_mod_p521_raw(mbedtls_mpi_uint *X, size_t X_limbs); #if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) -/** Fast quasi-reduction modulo p384 (FIPS 186-3 D.2.4) +/** Fast quasi-reduction modulo p384 * * \param[in,out] X The address of the MPI to be converted. * Must have exact limb size that stores a 768-bit MPI @@ -168,8 +168,7 @@ int mbedtls_ecp_mod_p384_raw(mbedtls_mpi_uint *X, size_t X_limbs); #if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) -/** Fast quasi-reduction modulo p192k1 = 2^192 - R, - * with R = 2^32 + 2^12 + 2^8 + 2^7 + 2^6 + 2^3 + 1 = 0x01000011C9 +/** Fast quasi-reduction modulo p192k1 = 2^192 - 0x01000011C9 * * \param[in,out] X The address of the MPI to be converted. * Must have exact limb size that stores a 384-bit MPI @@ -183,7 +182,6 @@ int mbedtls_ecp_mod_p384_raw(mbedtls_mpi_uint *X, size_t X_limbs); * \return \c 0 on success. * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if \p X does not have * twice as many limbs as the modulus. - * \return #MBEDTLS_ERR_ECP_ALLOC_FAILED if memory allocation failed. */ MBEDTLS_STATIC_TESTABLE int mbedtls_ecp_mod_p192k1_raw(mbedtls_mpi_uint *X, size_t X_limbs); @@ -192,8 +190,7 @@ int mbedtls_ecp_mod_p192k1_raw(mbedtls_mpi_uint *X, size_t X_limbs); #if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) -/** Fast quasi-reduction modulo p224k1 = 2^224 - R, - * with R = 2^32 + 2^12 + 2^11 + 2^9 + 2^7 + 2^4 + 2 + 1 = 0x0100001A93 +/** Fast quasi-reduction modulo p224k1 = 2^224 - 0x0100001A93 * * \param[in,out] X The address of the MPI to be converted. * Must have exact limb size that stores a 448-bit MPI @@ -207,7 +204,6 @@ int mbedtls_ecp_mod_p192k1_raw(mbedtls_mpi_uint *X, size_t X_limbs); * \return \c 0 on success. * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if \p X does not have * twice as many limbs as the modulus. - * \return #MBEDTLS_ERR_ECP_ALLOC_FAILED if memory allocation failed. */ MBEDTLS_STATIC_TESTABLE int mbedtls_ecp_mod_p224k1_raw(mbedtls_mpi_uint *X, size_t X_limbs); @@ -216,8 +212,7 @@ int mbedtls_ecp_mod_p224k1_raw(mbedtls_mpi_uint *X, size_t X_limbs); #if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) -/** Fast quasi-reduction modulo p256k1 = 2^256 - R, - * with R = 2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1 = 0x01000003D1 +/** Fast quasi-reduction modulo p256k1 = 2^256 - 0x01000003D1 * * \param[in,out] X The address of the MPI to be converted. * Must have exact limb size that stores a 512-bit MPI @@ -231,7 +226,6 @@ int mbedtls_ecp_mod_p224k1_raw(mbedtls_mpi_uint *X, size_t X_limbs); * \return \c 0 on success. * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if \p X does not have * twice as many limbs as the modulus. - * \return #MBEDTLS_ERR_ECP_ALLOC_FAILED if memory allocation failed. */ MBEDTLS_STATIC_TESTABLE int mbedtls_ecp_mod_p256k1_raw(mbedtls_mpi_uint *X, size_t X_limbs); @@ -247,12 +241,13 @@ 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. * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if \p X does not have * twice as many limbs as the modulus. - * \return #MBEDTLS_ERR_ECP_ALLOC_FAILED if memory allocation failed. */ MBEDTLS_STATIC_TESTABLE int mbedtls_ecp_mod_p255_raw(mbedtls_mpi_uint *X, size_t X_limbs); @@ -262,29 +257,26 @@ int mbedtls_ecp_mod_p255_raw(mbedtls_mpi_uint *X, size_t X_limbs); #if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) /** Fast quasi-reduction modulo p448 = 2^448 - 2^224 - 1 - * Write X as A0 + 2^448 A1 and A1 as B0 + 2^224 B1, and return A0 + A1 + B1 + - * (B0 + B1) * 2^224. * * \param[in,out] X The address of the MPI to be converted. * Must have exact limb size that stores a 896-bit MPI - * (double the bitlength of the modulus). Upon return - * holds the reduced value which is in range `0 <= X < - * N` (where N is the modulus). The bitlength of the - * reduced value is the same as that of the modulus - * (448 bits). + * (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 the same as + * that of the modulus (448 bits). * \param[in] X_limbs The length of \p X in limbs. * * \return \c 0 on Success. * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if \p X does not have * twice as many limbs as the modulus. - * \return #MBEDTLS_ERR_ECP_ALLOC_FAILED if memory allocation - * failed. */ MBEDTLS_STATIC_TESTABLE int mbedtls_ecp_mod_p448_raw(mbedtls_mpi_uint *X, size_t X_limbs); #endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */ +#if defined(MBEDTLS_ECP_WITH_MPI_UINT) /** Initialise a modulus with hard-coded const curve data. * * \note The caller is responsible for the \p N modulus' memory. @@ -306,7 +298,8 @@ MBEDTLS_STATIC_TESTABLE int mbedtls_ecp_modulus_setup(mbedtls_mpi_mod_modulus *N, const mbedtls_ecp_group_id id, const mbedtls_ecp_modulus_type ctype); +#endif /* MBEDTLS_ECP_WITH_MPI_UINT */ -#endif /* MBEDTLS_TEST_HOOKS && MBEDTLS_ECP_C */ +#endif /* MBEDTLS_TEST_HOOKS && MBEDTLS_ECP_LIGHT */ #endif /* MBEDTLS_ECP_INVASIVE_H */ diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function index e0ced66eff..ddeda55e6f 100644 --- a/tests/suites/test_suite_ecp.function +++ b/tests/suites/test_suite_ecp.function @@ -1671,7 +1671,12 @@ void ecp_mod_p_generic_raw(int curve_id, mbedtls_mpi_uint c = mbedtls_mpi_core_sub(X, X, N, limbs_N); (void) mbedtls_mpi_core_add_if(X, N, limbs_N, (unsigned) c); #endif + /* Checking that the result is equal to the expected value is enough, + * but in case of failures, it's useful to know if the incorrect result + * had the correct bitlength or not / was in the correct range or not. */ TEST_LE_U(mbedtls_mpi_core_bitlen(X, limbs_X), curve_bits); + /* This only works because we know from above the top limbs of X are 0. */ + TEST_EQUAL(MBEDTLS_CT_TRUE, mbedtls_mpi_core_lt_ct(X, N, limbs_N)); TEST_MEMORY_COMPARE(X, bytes, res, bytes); exit: