summaryrefslogtreecommitdiffstats
path: root/thirdparty/mbedtls/library/ecp.c
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/mbedtls/library/ecp.c')
-rw-r--r--thirdparty/mbedtls/library/ecp.c1380
1 files changed, 718 insertions, 662 deletions
diff --git a/thirdparty/mbedtls/library/ecp.c b/thirdparty/mbedtls/library/ecp.c
index 31a6b9e305..427059bb53 100644
--- a/thirdparty/mbedtls/library/ecp.c
+++ b/thirdparty/mbedtls/library/ecp.c
@@ -60,187 +60,35 @@
#if defined(MBEDTLS_ECP_INTERNAL_ALT)
#endif
-#if defined(MBEDTLS_ECP_C)
+#if defined(MBEDTLS_ECP_LIGHT)
#include "mbedtls/ecp.h"
#include "mbedtls/threading.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
-#include "mbedtls/bn_mul.h"
+#include "bn_mul.h"
#include "ecp_invasive.h"
#include <string.h>
#if !defined(MBEDTLS_ECP_ALT)
-/* Parameter validation macros based on platform_util.h */
-#define ECP_VALIDATE_RET(cond) \
- MBEDTLS_INTERNAL_VALIDATE_RET(cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA)
-#define ECP_VALIDATE(cond) \
- MBEDTLS_INTERNAL_VALIDATE(cond)
-
#include "mbedtls/platform.h"
-#include "mbedtls/ecp_internal.h"
-
-#if !defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
-#if defined(MBEDTLS_HMAC_DRBG_C)
-#include "mbedtls/hmac_drbg.h"
-#elif defined(MBEDTLS_CTR_DRBG_C)
-#include "mbedtls/ctr_drbg.h"
-#else
-#error \
- "Invalid configuration detected. Include check_config.h to ensure that the configuration is valid."
-#endif
-#endif /* MBEDTLS_ECP_NO_INTERNAL_RNG */
+#include "ecp_internal_alt.h"
#if defined(MBEDTLS_SELF_TEST)
/*
* Counts of point addition and doubling, and field multiplications.
* Used to test resistance of point multiplication to simple timing attacks.
*/
-static unsigned long add_count, dbl_count, mul_count;
+#if defined(MBEDTLS_ECP_C)
+static unsigned long add_count, dbl_count;
+#endif /* MBEDTLS_ECP_C */
+static unsigned long mul_count;
#endif
-#if !defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
-/*
- * Currently ecp_mul() takes a RNG function as an argument, used for
- * side-channel protection, but it can be NULL. The initial reasoning was
- * that people will pass non-NULL RNG when they care about side-channels, but
- * unfortunately we have some APIs that call ecp_mul() with a NULL RNG, with
- * no opportunity for the user to do anything about it.
- *
- * The obvious strategies for addressing that include:
- * - change those APIs so that they take RNG arguments;
- * - require a global RNG to be available to all crypto modules.
- *
- * Unfortunately those would break compatibility. So what we do instead is
- * have our own internal DRBG instance, seeded from the secret scalar.
- *
- * The following is a light-weight abstraction layer for doing that with
- * HMAC_DRBG (first choice) or CTR_DRBG.
- */
-
-#if defined(MBEDTLS_HMAC_DRBG_C)
-
-/* DRBG context type */
-typedef mbedtls_hmac_drbg_context ecp_drbg_context;
-
-/* DRBG context init */
-static inline void ecp_drbg_init(ecp_drbg_context *ctx)
-{
- mbedtls_hmac_drbg_init(ctx);
-}
-
-/* DRBG context free */
-static inline void ecp_drbg_free(ecp_drbg_context *ctx)
-{
- mbedtls_hmac_drbg_free(ctx);
-}
-
-/* DRBG function */
-static inline int ecp_drbg_random(void *p_rng,
- unsigned char *output, size_t output_len)
-{
- return mbedtls_hmac_drbg_random(p_rng, output, output_len);
-}
-
-/* DRBG context seeding */
-static int ecp_drbg_seed(ecp_drbg_context *ctx,
- const mbedtls_mpi *secret, size_t secret_len)
-{
- int ret;
- unsigned char secret_bytes[MBEDTLS_ECP_MAX_BYTES];
- /* The list starts with strong hashes */
- const mbedtls_md_type_t md_type =
- (mbedtls_md_type_t) (mbedtls_md_list()[0]);
- const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_type);
-
- if (secret_len > MBEDTLS_ECP_MAX_BYTES) {
- ret = MBEDTLS_ERR_ECP_RANDOM_FAILED;
- goto cleanup;
- }
-
- MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(secret,
- secret_bytes, secret_len));
-
- ret = mbedtls_hmac_drbg_seed_buf(ctx, md_info, secret_bytes, secret_len);
-
-cleanup:
- mbedtls_platform_zeroize(secret_bytes, secret_len);
-
- return ret;
-}
-
-#elif defined(MBEDTLS_CTR_DRBG_C)
-
-/* DRBG context type */
-typedef mbedtls_ctr_drbg_context ecp_drbg_context;
-
-/* DRBG context init */
-static inline void ecp_drbg_init(ecp_drbg_context *ctx)
-{
- mbedtls_ctr_drbg_init(ctx);
-}
-
-/* DRBG context free */
-static inline void ecp_drbg_free(ecp_drbg_context *ctx)
-{
- mbedtls_ctr_drbg_free(ctx);
-}
-
-/* DRBG function */
-static inline int ecp_drbg_random(void *p_rng,
- unsigned char *output, size_t output_len)
-{
- return mbedtls_ctr_drbg_random(p_rng, output, output_len);
-}
-
-/*
- * Since CTR_DRBG doesn't have a seed_buf() function the way HMAC_DRBG does,
- * we need to pass an entropy function when seeding. So we use a dummy
- * function for that, and pass the actual entropy as customisation string.
- * (During seeding of CTR_DRBG the entropy input and customisation string are
- * concatenated before being used to update the secret state.)
- */
-static int ecp_ctr_drbg_null_entropy(void *ctx, unsigned char *out, size_t len)
-{
- (void) ctx;
- memset(out, 0, len);
- return 0;
-}
-
-/* DRBG context seeding */
-static int ecp_drbg_seed(ecp_drbg_context *ctx,
- const mbedtls_mpi *secret, size_t secret_len)
-{
- int ret;
- unsigned char secret_bytes[MBEDTLS_ECP_MAX_BYTES];
-
- if (secret_len > MBEDTLS_ECP_MAX_BYTES) {
- ret = MBEDTLS_ERR_ECP_RANDOM_FAILED;
- goto cleanup;
- }
-
- MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(secret,
- secret_bytes, secret_len));
-
- ret = mbedtls_ctr_drbg_seed(ctx, ecp_ctr_drbg_null_entropy, NULL,
- secret_bytes, secret_len);
-
-cleanup:
- mbedtls_platform_zeroize(secret_bytes, secret_len);
-
- return ret;
-}
-
-#else
-#error \
- "Invalid configuration detected. Include check_config.h to ensure that the configuration is valid."
-#endif /* DRBG modules */
-#endif /* MBEDTLS_ECP_NO_INTERNAL_RNG */
-
#if defined(MBEDTLS_ECP_RESTARTABLE)
/*
* Maximum number of "basic operations" to be done in a row.
@@ -287,10 +135,6 @@ struct mbedtls_ecp_restart_mul {
ecp_rsm_comb_core, /* ecp_mul_comb_core() */
ecp_rsm_final_norm, /* do the final normalization */
} state;
-#if !defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
- ecp_drbg_context drbg_ctx;
- unsigned char drbg_seeded;
-#endif
};
/*
@@ -303,10 +147,6 @@ static void ecp_restart_rsm_init(mbedtls_ecp_restart_mul_ctx *ctx)
ctx->T = NULL;
ctx->T_size = 0;
ctx->state = ecp_rsm_init;
-#if !defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
- ecp_drbg_init(&ctx->drbg_ctx);
- ctx->drbg_seeded = 0;
-#endif
}
/*
@@ -329,10 +169,6 @@ static void ecp_restart_rsm_free(mbedtls_ecp_restart_mul_ctx *ctx)
mbedtls_free(ctx->T);
}
-#if !defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
- ecp_drbg_free(&ctx->drbg_ctx);
-#endif
-
ecp_restart_rsm_init(ctx);
}
@@ -380,7 +216,6 @@ static void ecp_restart_ma_free(mbedtls_ecp_restart_muladd_ctx *ctx)
*/
void mbedtls_ecp_restart_init(mbedtls_ecp_restart_ctx *ctx)
{
- ECP_VALIDATE(ctx != NULL);
ctx->ops_done = 0;
ctx->depth = 0;
ctx->rsm = NULL;
@@ -412,8 +247,6 @@ int mbedtls_ecp_check_budget(const mbedtls_ecp_group *grp,
mbedtls_ecp_restart_ctx *rs_ctx,
unsigned ops)
{
- ECP_VALIDATE_RET(grp != NULL);
-
if (rs_ctx != NULL && ecp_max_ops != 0) {
/* scale depending on curve size: the chosen reference is 256-bit,
* and multiplication is quadratic. Round to the closest integer. */
@@ -480,6 +313,22 @@ int mbedtls_ecp_check_budget(const mbedtls_ecp_group *grp,
#endif /* MBEDTLS_ECP_RESTARTABLE */
+#if defined(MBEDTLS_ECP_C)
+static void mpi_init_many(mbedtls_mpi *arr, size_t size)
+{
+ while (size--) {
+ mbedtls_mpi_init(arr++);
+ }
+}
+
+static void mpi_free_many(mbedtls_mpi *arr, size_t size)
+{
+ while (size--) {
+ mbedtls_mpi_free(arr++);
+ }
+}
+#endif /* MBEDTLS_ECP_C */
+
/*
* List of supported curves:
* - internal ID
@@ -488,9 +337,9 @@ int mbedtls_ecp_check_budget(const mbedtls_ecp_group *grp,
* - readable name
*
* Curves are listed in order: largest curves first, and for a given size,
- * fastest curves first. This provides the default order for the SSL module.
+ * fastest curves first.
*
- * Reminder: update profiles in x509_crt.c when adding a new curves!
+ * Reminder: update profiles in x509_crt.c and ssl_tls.c when adding a new curve!
*/
static const mbedtls_ecp_curve_info ecp_supported_curves[] =
{
@@ -652,8 +501,6 @@ mbedtls_ecp_curve_type mbedtls_ecp_get_type(const mbedtls_ecp_group *grp)
*/
void mbedtls_ecp_point_init(mbedtls_ecp_point *pt)
{
- ECP_VALIDATE(pt != NULL);
-
mbedtls_mpi_init(&pt->X);
mbedtls_mpi_init(&pt->Y);
mbedtls_mpi_init(&pt->Z);
@@ -664,8 +511,6 @@ void mbedtls_ecp_point_init(mbedtls_ecp_point *pt)
*/
void mbedtls_ecp_group_init(mbedtls_ecp_group *grp)
{
- ECP_VALIDATE(grp != NULL);
-
grp->id = MBEDTLS_ECP_DP_NONE;
mbedtls_mpi_init(&grp->P);
mbedtls_mpi_init(&grp->A);
@@ -688,8 +533,6 @@ void mbedtls_ecp_group_init(mbedtls_ecp_group *grp)
*/
void mbedtls_ecp_keypair_init(mbedtls_ecp_keypair *key)
{
- ECP_VALIDATE(key != NULL);
-
mbedtls_ecp_group_init(&key->grp);
mbedtls_mpi_init(&key->d);
mbedtls_ecp_point_init(&key->Q);
@@ -710,6 +553,19 @@ void mbedtls_ecp_point_free(mbedtls_ecp_point *pt)
}
/*
+ * Check that the comb table (grp->T) is static initialized.
+ */
+static int ecp_group_is_static_comb_table(const mbedtls_ecp_group *grp)
+{
+#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1
+ return grp->T != NULL && grp->T_size == 0;
+#else
+ (void) grp;
+ return 0;
+#endif
+}
+
+/*
* Unallocate (the components of) a group
*/
void mbedtls_ecp_group_free(mbedtls_ecp_group *grp)
@@ -721,14 +577,17 @@ void mbedtls_ecp_group_free(mbedtls_ecp_group *grp)
}
if (grp->h != 1) {
- mbedtls_mpi_free(&grp->P);
mbedtls_mpi_free(&grp->A);
mbedtls_mpi_free(&grp->B);
mbedtls_ecp_point_free(&grp->G);
+
+#if !defined(MBEDTLS_ECP_WITH_MPI_UINT)
mbedtls_mpi_free(&grp->N);
+ mbedtls_mpi_free(&grp->P);
+#endif
}
- if (grp->T != NULL) {
+ if (!ecp_group_is_static_comb_table(grp) && grp->T != NULL) {
for (i = 0; i < grp->T_size; i++) {
mbedtls_ecp_point_free(&grp->T[i]);
}
@@ -758,9 +617,6 @@ void mbedtls_ecp_keypair_free(mbedtls_ecp_keypair *key)
int mbedtls_ecp_copy(mbedtls_ecp_point *P, const mbedtls_ecp_point *Q)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
- ECP_VALIDATE_RET(P != NULL);
- ECP_VALIDATE_RET(Q != NULL);
-
MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&P->X, &Q->X));
MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&P->Y, &Q->Y));
MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&P->Z, &Q->Z));
@@ -774,9 +630,6 @@ cleanup:
*/
int mbedtls_ecp_group_copy(mbedtls_ecp_group *dst, const mbedtls_ecp_group *src)
{
- ECP_VALIDATE_RET(dst != NULL);
- ECP_VALIDATE_RET(src != NULL);
-
return mbedtls_ecp_group_load(dst, src->id);
}
@@ -786,8 +639,6 @@ int mbedtls_ecp_group_copy(mbedtls_ecp_group *dst, const mbedtls_ecp_group *src)
int mbedtls_ecp_set_zero(mbedtls_ecp_point *pt)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
- ECP_VALIDATE_RET(pt != NULL);
-
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->X, 1));
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Y, 1));
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Z, 0));
@@ -801,8 +652,6 @@ cleanup:
*/
int mbedtls_ecp_is_zero(mbedtls_ecp_point *pt)
{
- ECP_VALIDATE_RET(pt != NULL);
-
return mbedtls_mpi_cmp_int(&pt->Z, 0) == 0;
}
@@ -812,9 +661,6 @@ int mbedtls_ecp_is_zero(mbedtls_ecp_point *pt)
int mbedtls_ecp_point_cmp(const mbedtls_ecp_point *P,
const mbedtls_ecp_point *Q)
{
- ECP_VALIDATE_RET(P != NULL);
- ECP_VALIDATE_RET(Q != NULL);
-
if (mbedtls_mpi_cmp_mpi(&P->X, &Q->X) == 0 &&
mbedtls_mpi_cmp_mpi(&P->Y, &Q->Y) == 0 &&
mbedtls_mpi_cmp_mpi(&P->Z, &Q->Z) == 0) {
@@ -831,10 +677,6 @@ int mbedtls_ecp_point_read_string(mbedtls_ecp_point *P, int radix,
const char *x, const char *y)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
- ECP_VALIDATE_RET(P != NULL);
- ECP_VALIDATE_RET(x != NULL);
- ECP_VALIDATE_RET(y != NULL);
-
MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&P->X, radix, x));
MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&P->Y, radix, y));
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&P->Z, 1));
@@ -853,12 +695,10 @@ int mbedtls_ecp_point_write_binary(const mbedtls_ecp_group *grp,
{
int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
size_t plen;
- ECP_VALIDATE_RET(grp != NULL);
- ECP_VALIDATE_RET(P != NULL);
- ECP_VALIDATE_RET(olen != NULL);
- ECP_VALIDATE_RET(buf != NULL);
- ECP_VALIDATE_RET(format == MBEDTLS_ECP_PF_UNCOMPRESSED ||
- format == MBEDTLS_ECP_PF_COMPRESSED);
+ if (format != MBEDTLS_ECP_PF_UNCOMPRESSED &&
+ format != MBEDTLS_ECP_PF_COMPRESSED) {
+ return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
+ }
plen = mbedtls_mpi_size(&grp->P);
@@ -916,6 +756,13 @@ cleanup:
return ret;
}
+#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
+static int mbedtls_ecp_sw_derive_y(const mbedtls_ecp_group *grp,
+ const mbedtls_mpi *X,
+ mbedtls_mpi *Y,
+ int parity_bit);
+#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */
+
/*
* Import a point from unsigned binary data (SEC1 2.3.4 and RFC7748)
*/
@@ -925,10 +772,6 @@ int mbedtls_ecp_point_read_binary(const mbedtls_ecp_group *grp,
{
int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
size_t plen;
- ECP_VALIDATE_RET(grp != NULL);
- ECP_VALIDATE_RET(pt != NULL);
- ECP_VALIDATE_RET(buf != NULL);
-
if (ilen < 1) {
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
@@ -962,18 +805,29 @@ int mbedtls_ecp_point_read_binary(const mbedtls_ecp_group *grp,
}
}
- if (buf[0] != 0x04) {
- return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
- }
-
- if (ilen != 2 * plen + 1) {
+ if (ilen < 1 + plen) {
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pt->X, buf + 1, plen));
- MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pt->Y,
- buf + 1 + plen, plen));
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Z, 1));
+
+ if (buf[0] == 0x04) {
+ /* format == MBEDTLS_ECP_PF_UNCOMPRESSED */
+ if (ilen != 1 + plen * 2) {
+ return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
+ }
+ return mbedtls_mpi_read_binary(&pt->Y, buf + 1 + plen, plen);
+ } else if (buf[0] == 0x02 || buf[0] == 0x03) {
+ /* format == MBEDTLS_ECP_PF_COMPRESSED */
+ if (ilen != 1 + plen) {
+ return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
+ }
+ return mbedtls_ecp_sw_derive_y(grp, &pt->X, &pt->Y,
+ (buf[0] & 1));
+ } else {
+ return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
+ }
}
#endif
@@ -993,11 +847,6 @@ int mbedtls_ecp_tls_read_point(const mbedtls_ecp_group *grp,
{
unsigned char data_len;
const unsigned char *buf_start;
- ECP_VALIDATE_RET(grp != NULL);
- ECP_VALIDATE_RET(pt != NULL);
- ECP_VALIDATE_RET(buf != NULL);
- ECP_VALIDATE_RET(*buf != NULL);
-
/*
* We must have at least two bytes (1 for length, at least one for data)
*/
@@ -1030,12 +879,10 @@ int mbedtls_ecp_tls_write_point(const mbedtls_ecp_group *grp, const mbedtls_ecp_
unsigned char *buf, size_t blen)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
- ECP_VALIDATE_RET(grp != NULL);
- ECP_VALIDATE_RET(pt != NULL);
- ECP_VALIDATE_RET(olen != NULL);
- ECP_VALIDATE_RET(buf != NULL);
- ECP_VALIDATE_RET(format == MBEDTLS_ECP_PF_UNCOMPRESSED ||
- format == MBEDTLS_ECP_PF_COMPRESSED);
+ if (format != MBEDTLS_ECP_PF_UNCOMPRESSED &&
+ format != MBEDTLS_ECP_PF_COMPRESSED) {
+ return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
+ }
/*
* buffer length must be at least one, for our length byte
@@ -1066,10 +913,6 @@ int mbedtls_ecp_tls_read_group(mbedtls_ecp_group *grp,
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_ecp_group_id grp_id;
- ECP_VALIDATE_RET(grp != NULL);
- ECP_VALIDATE_RET(buf != NULL);
- ECP_VALIDATE_RET(*buf != NULL);
-
if ((ret = mbedtls_ecp_tls_read_group_id(&grp_id, buf, len)) != 0) {
return ret;
}
@@ -1086,10 +929,6 @@ int mbedtls_ecp_tls_read_group_id(mbedtls_ecp_group_id *grp,
{
uint16_t tls_id;
const mbedtls_ecp_curve_info *curve_info;
- ECP_VALIDATE_RET(grp != NULL);
- ECP_VALIDATE_RET(buf != NULL);
- ECP_VALIDATE_RET(*buf != NULL);
-
/*
* We expect at least three bytes (see below)
*/
@@ -1107,9 +946,8 @@ int mbedtls_ecp_tls_read_group_id(mbedtls_ecp_group_id *grp,
/*
* Next two bytes are the namedcurve value
*/
- tls_id = *(*buf)++;
- tls_id <<= 8;
- tls_id |= *(*buf)++;
+ tls_id = MBEDTLS_GET_UINT16_BE(*buf, 0);
+ *buf += 2;
if ((curve_info = mbedtls_ecp_curve_info_from_tls_id(tls_id)) == NULL) {
return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
@@ -1127,10 +965,6 @@ int mbedtls_ecp_tls_write_group(const mbedtls_ecp_group *grp, size_t *olen,
unsigned char *buf, size_t blen)
{
const mbedtls_ecp_curve_info *curve_info;
- ECP_VALIDATE_RET(grp != NULL);
- ECP_VALIDATE_RET(buf != NULL);
- ECP_VALIDATE_RET(olen != NULL);
-
if ((curve_info = mbedtls_ecp_curve_info_from_grp_id(grp->id)) == NULL) {
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
@@ -1234,17 +1068,13 @@ cleanup:
* Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_sub_mpi
* N->s < 0 is a very fast test, which fails only if N is 0
*/
-#define MOD_SUB(N) \
- while ((N).s < 0 && mbedtls_mpi_cmp_int(&(N), 0) != 0) \
- MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&(N), &(N), &grp->P))
-
-#if (defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) && \
- !(defined(MBEDTLS_ECP_NO_FALLBACK) && \
- defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) && \
- defined(MBEDTLS_ECP_ADD_MIXED_ALT))) || \
- (defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) && \
- !(defined(MBEDTLS_ECP_NO_FALLBACK) && \
- defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT)))
+#define MOD_SUB(N) \
+ do { \
+ while ((N)->s < 0 && mbedtls_mpi_cmp_int((N), 0) != 0) \
+ MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi((N), (N), &grp->P)); \
+ } while (0)
+
+MBEDTLS_MAYBE_UNUSED
static inline int mbedtls_mpi_sub_mod(const mbedtls_ecp_group *grp,
mbedtls_mpi *X,
const mbedtls_mpi *A,
@@ -1252,20 +1082,19 @@ static inline int mbedtls_mpi_sub_mod(const mbedtls_ecp_group *grp,
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(X, A, B));
- MOD_SUB(*X);
+ MOD_SUB(X);
cleanup:
return ret;
}
-#endif /* All functions referencing mbedtls_mpi_sub_mod() are alt-implemented without fallback */
/*
* Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_add_mpi and mbedtls_mpi_mul_int.
* We known P, N and the result are positive, so sub_abs is correct, and
* a bit faster.
*/
-#define MOD_ADD(N) \
- while (mbedtls_mpi_cmp_mpi(&(N), &grp->P) >= 0) \
- MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&(N), &(N), &grp->P))
+#define MOD_ADD(N) \
+ while (mbedtls_mpi_cmp_mpi((N), &grp->P) >= 0) \
+ MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs((N), (N), &grp->P))
static inline int mbedtls_mpi_add_mod(const mbedtls_ecp_group *grp,
mbedtls_mpi *X,
@@ -1274,28 +1103,201 @@ static inline int mbedtls_mpi_add_mod(const mbedtls_ecp_group *grp,
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(X, A, B));
- MOD_ADD(*X);
+ MOD_ADD(X);
cleanup:
return ret;
}
-#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) && \
- !(defined(MBEDTLS_ECP_NO_FALLBACK) && \
- defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) && \
- defined(MBEDTLS_ECP_ADD_MIXED_ALT))
+MBEDTLS_MAYBE_UNUSED
+static inline int mbedtls_mpi_mul_int_mod(const mbedtls_ecp_group *grp,
+ mbedtls_mpi *X,
+ const mbedtls_mpi *A,
+ mbedtls_mpi_uint c)
+{
+ int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+ MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(X, A, c));
+ MOD_ADD(X);
+cleanup:
+ return ret;
+}
+
+MBEDTLS_MAYBE_UNUSED
+static inline int mbedtls_mpi_sub_int_mod(const mbedtls_ecp_group *grp,
+ mbedtls_mpi *X,
+ const mbedtls_mpi *A,
+ mbedtls_mpi_uint c)
+{
+ int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+ MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(X, A, c));
+ MOD_SUB(X);
+cleanup:
+ return ret;
+}
+
+#define MPI_ECP_SUB_INT(X, A, c) \
+ MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int_mod(grp, X, A, c))
+
+MBEDTLS_MAYBE_UNUSED
static inline int mbedtls_mpi_shift_l_mod(const mbedtls_ecp_group *grp,
mbedtls_mpi *X,
size_t count)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(X, count));
- MOD_ADD(*X);
+ MOD_ADD(X);
+cleanup:
+ return ret;
+}
+
+/*
+ * Macro wrappers around ECP modular arithmetic
+ *
+ * Currently, these wrappers are defined via the bignum module.
+ */
+
+#define MPI_ECP_ADD(X, A, B) \
+ MBEDTLS_MPI_CHK(mbedtls_mpi_add_mod(grp, X, A, B))
+
+#define MPI_ECP_SUB(X, A, B) \
+ MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, X, A, B))
+
+#define MPI_ECP_MUL(X, A, B) \
+ MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, X, A, B))
+
+#define MPI_ECP_SQR(X, A) \
+ MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, X, A, A))
+
+#define MPI_ECP_MUL_INT(X, A, c) \
+ MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int_mod(grp, X, A, c))
+
+#define MPI_ECP_INV(dst, src) \
+ MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod((dst), (src), &grp->P))
+
+#define MPI_ECP_MOV(X, A) \
+ MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A))
+
+#define MPI_ECP_SHIFT_L(X, count) \
+ MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l_mod(grp, X, count))
+
+#define MPI_ECP_LSET(X, c) \
+ MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, c))
+
+#define MPI_ECP_CMP_INT(X, c) \
+ mbedtls_mpi_cmp_int(X, c)
+
+#define MPI_ECP_CMP(X, Y) \
+ mbedtls_mpi_cmp_mpi(X, Y)
+
+/* Needs f_rng, p_rng to be defined. */
+#define MPI_ECP_RAND(X) \
+ MBEDTLS_MPI_CHK(mbedtls_mpi_random((X), 2, &grp->P, f_rng, p_rng))
+
+/* Conditional negation
+ * Needs grp and a temporary MPI tmp to be defined. */
+#define MPI_ECP_COND_NEG(X, cond) \
+ do \
+ { \
+ unsigned char nonzero = mbedtls_mpi_cmp_int((X), 0) != 0; \
+ MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&tmp, &grp->P, (X))); \
+ MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign((X), &tmp, \
+ nonzero & cond)); \
+ } while (0)
+
+#define MPI_ECP_NEG(X) MPI_ECP_COND_NEG((X), 1)
+
+#define MPI_ECP_VALID(X) \
+ ((X)->p != NULL)
+
+#define MPI_ECP_COND_ASSIGN(X, Y, cond) \
+ MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign((X), (Y), (cond)))
+
+#define MPI_ECP_COND_SWAP(X, Y, cond) \
+ MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_swap((X), (Y), (cond)))
+
+#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
+
+/*
+ * Computes the right-hand side of the Short Weierstrass equation
+ * RHS = X^3 + A X + B
+ */
+static int ecp_sw_rhs(const mbedtls_ecp_group *grp,
+ mbedtls_mpi *rhs,
+ const mbedtls_mpi *X)
+{
+ int ret;
+
+ /* Compute X^3 + A X + B as X (X^2 + A) + B */
+ MPI_ECP_SQR(rhs, X);
+
+ /* Special case for A = -3 */
+ if (mbedtls_ecp_group_a_is_minus_3(grp)) {
+ MPI_ECP_SUB_INT(rhs, rhs, 3);
+ } else {
+ MPI_ECP_ADD(rhs, rhs, &grp->A);
+ }
+
+ MPI_ECP_MUL(rhs, rhs, X);
+ MPI_ECP_ADD(rhs, rhs, &grp->B);
+
cleanup:
return ret;
}
-#endif \
- /* All functions referencing mbedtls_mpi_shift_l_mod() are alt-implemented without fallback */
+/*
+ * Derive Y from X and a parity bit
+ */
+static int mbedtls_ecp_sw_derive_y(const mbedtls_ecp_group *grp,
+ const mbedtls_mpi *X,
+ mbedtls_mpi *Y,
+ int parity_bit)
+{
+ /* w = y^2 = x^3 + ax + b
+ * y = sqrt(w) = w^((p+1)/4) mod p (for prime p where p = 3 mod 4)
+ *
+ * Note: this method for extracting square root does not validate that w
+ * was indeed a square so this function will return garbage in Y if X
+ * does not correspond to a point on the curve.
+ */
+
+ /* Check prerequisite p = 3 mod 4 */
+ if (mbedtls_mpi_get_bit(&grp->P, 0) != 1 ||
+ mbedtls_mpi_get_bit(&grp->P, 1) != 1) {
+ return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
+ }
+
+ int ret;
+ mbedtls_mpi exp;
+ mbedtls_mpi_init(&exp);
+
+ /* use Y to store intermediate result, actually w above */
+ MBEDTLS_MPI_CHK(ecp_sw_rhs(grp, Y, X));
+
+ /* w = y^2 */ /* Y contains y^2 intermediate result */
+ /* exp = ((p+1)/4) */
+ MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&exp, &grp->P, 1));
+ MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&exp, 2));
+ /* sqrt(w) = w^((p+1)/4) mod p (for prime p where p = 3 mod 4) */
+ MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(Y, Y /*y^2*/, &exp, &grp->P, NULL));
+
+ /* check parity bit match or else invert Y */
+ /* This quick inversion implementation is valid because Y != 0 for all
+ * Short Weierstrass curves supported by mbedtls, as each supported curve
+ * has an order that is a large prime, so each supported curve does not
+ * have any point of order 2, and a point with Y == 0 would be of order 2 */
+ if (mbedtls_mpi_get_bit(Y, 0) != parity_bit) {
+ MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(Y, &grp->P, Y));
+ }
+
+cleanup:
+
+ mbedtls_mpi_free(&exp);
+ return ret;
+}
+#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */
+
+#if defined(MBEDTLS_ECP_C)
#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
/*
* For curves in short Weierstrass form, we do all the internal operations in
@@ -1311,7 +1313,7 @@ cleanup:
*/
static int ecp_normalize_jac(const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt)
{
- if (mbedtls_mpi_cmp_int(&pt->Z, 0) == 0) {
+ if (MPI_ECP_CMP_INT(&pt->Z, 0) == 0) {
return 0;
}
@@ -1325,30 +1327,20 @@ static int ecp_normalize_jac(const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt
return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
#else
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
- mbedtls_mpi Zi, ZZi;
- mbedtls_mpi_init(&Zi); mbedtls_mpi_init(&ZZi);
+ mbedtls_mpi T;
+ mbedtls_mpi_init(&T);
- /*
- * X = X / Z^2 mod p
- */
- MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&Zi, &pt->Z, &grp->P));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &ZZi, &Zi, &Zi));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &pt->X, &pt->X, &ZZi));
+ MPI_ECP_INV(&T, &pt->Z); /* T <- 1 / Z */
+ MPI_ECP_MUL(&pt->Y, &pt->Y, &T); /* Y' <- Y*T = Y / Z */
+ MPI_ECP_SQR(&T, &T); /* T <- T^2 = 1 / Z^2 */
+ MPI_ECP_MUL(&pt->X, &pt->X, &T); /* X <- X * T = X / Z^2 */
+ MPI_ECP_MUL(&pt->Y, &pt->Y, &T); /* Y'' <- Y' * T = Y / Z^3 */
- /*
- * Y = Y / Z^3 mod p
- */
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &pt->Y, &pt->Y, &ZZi));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &pt->Y, &pt->Y, &Zi));
-
- /*
- * Z = 1
- */
- MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Z, 1));
+ MPI_ECP_LSET(&pt->Z, 1);
cleanup:
- mbedtls_mpi_free(&Zi); mbedtls_mpi_free(&ZZi);
+ mbedtls_mpi_free(&T);
return ret;
#endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || !defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) */
@@ -1383,50 +1375,54 @@ static int ecp_normalize_jac_many(const mbedtls_ecp_group *grp,
#else
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t i;
- mbedtls_mpi *c, u, Zi, ZZi;
+ mbedtls_mpi *c, t;
if ((c = mbedtls_calloc(T_size, sizeof(mbedtls_mpi))) == NULL) {
return MBEDTLS_ERR_ECP_ALLOC_FAILED;
}
- for (i = 0; i < T_size; i++) {
- mbedtls_mpi_init(&c[i]);
- }
-
- mbedtls_mpi_init(&u); mbedtls_mpi_init(&Zi); mbedtls_mpi_init(&ZZi);
+ mbedtls_mpi_init(&t);
+ mpi_init_many(c, T_size);
/*
- * c[i] = Z_0 * ... * Z_i
+ * c[i] = Z_0 * ... * Z_i, i = 0,..,n := T_size-1
*/
- MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&c[0], &T[0]->Z));
+ MPI_ECP_MOV(&c[0], &T[0]->Z);
for (i = 1; i < T_size; i++) {
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &c[i], &c[i-1], &T[i]->Z));
+ MPI_ECP_MUL(&c[i], &c[i-1], &T[i]->Z);
}
/*
- * u = 1 / (Z_0 * ... * Z_n) mod P
+ * c[n] = 1 / (Z_0 * ... * Z_n) mod P
*/
- MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&u, &c[T_size-1], &grp->P));
+ MPI_ECP_INV(&c[T_size-1], &c[T_size-1]);
for (i = T_size - 1;; i--) {
- /*
- * Zi = 1 / Z_i mod p
- * u = 1 / (Z_0 * ... * Z_i) mod P
+ /* At the start of iteration i (note that i decrements), we have
+ * - c[j] = Z_0 * .... * Z_j for j < i,
+ * - c[j] = 1 / (Z_0 * .... * Z_j) for j == i,
+ *
+ * This is maintained via
+ * - c[i-1] <- c[i] * Z_i
+ *
+ * We also derive 1/Z_i = c[i] * c[i-1] for i>0 and use that
+ * to do the actual normalization. For i==0, we already have
+ * c[0] = 1 / Z_0.
*/
- if (i == 0) {
- MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Zi, &u));
+
+ if (i > 0) {
+ /* Compute 1/Z_i and establish invariant for the next iteration. */
+ MPI_ECP_MUL(&t, &c[i], &c[i-1]);
+ MPI_ECP_MUL(&c[i-1], &c[i], &T[i]->Z);
} else {
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &Zi, &u, &c[i-1]));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &u, &u, &T[i]->Z));
+ MPI_ECP_MOV(&t, &c[0]);
}
- /*
- * proceed as in normalize()
- */
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &ZZi, &Zi, &Zi));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T[i]->X, &T[i]->X, &ZZi));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T[i]->Y, &T[i]->Y, &ZZi));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T[i]->Y, &T[i]->Y, &Zi));
+ /* Now t holds 1 / Z_i; normalize as in ecp_normalize_jac() */
+ MPI_ECP_MUL(&T[i]->Y, &T[i]->Y, &t);
+ MPI_ECP_SQR(&t, &t);
+ MPI_ECP_MUL(&T[i]->X, &T[i]->X, &t);
+ MPI_ECP_MUL(&T[i]->Y, &T[i]->Y, &t);
/*
* Post-precessing: reclaim some memory by shrinking coordinates
@@ -1436,7 +1432,8 @@ static int ecp_normalize_jac_many(const mbedtls_ecp_group *grp,
*/
MBEDTLS_MPI_CHK(mbedtls_mpi_shrink(&T[i]->X, grp->P.n));
MBEDTLS_MPI_CHK(mbedtls_mpi_shrink(&T[i]->Y, grp->P.n));
- mbedtls_mpi_free(&T[i]->Z);
+
+ MPI_ECP_LSET(&T[i]->Z, 1);
if (i == 0) {
break;
@@ -1445,10 +1442,8 @@ static int ecp_normalize_jac_many(const mbedtls_ecp_group *grp,
cleanup:
- mbedtls_mpi_free(&u); mbedtls_mpi_free(&Zi); mbedtls_mpi_free(&ZZi);
- for (i = 0; i < T_size; i++) {
- mbedtls_mpi_free(&c[i]);
- }
+ mbedtls_mpi_free(&t);
+ mpi_free_many(c, T_size);
mbedtls_free(c);
return ret;
@@ -1464,19 +1459,13 @@ static int ecp_safe_invert_jac(const mbedtls_ecp_group *grp,
unsigned char inv)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
- unsigned char nonzero;
- mbedtls_mpi mQY;
-
- mbedtls_mpi_init(&mQY);
+ mbedtls_mpi tmp;
+ mbedtls_mpi_init(&tmp);
- /* Use the fact that -Q.Y mod P = P - Q.Y unless Q.Y == 0 */
- MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&mQY, &grp->P, &Q->Y));
- nonzero = mbedtls_mpi_cmp_int(&Q->Y, 0) != 0;
- MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign(&Q->Y, &mQY, inv & nonzero));
+ MPI_ECP_COND_NEG(&Q->Y, inv);
cleanup:
- mbedtls_mpi_free(&mQY);
-
+ mbedtls_mpi_free(&tmp);
return ret;
}
@@ -1495,7 +1484,8 @@ cleanup:
* 3M + 6S + 1a otherwise
*/
static int ecp_double_jac(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
- const mbedtls_ecp_point *P)
+ const mbedtls_ecp_point *P,
+ mbedtls_mpi tmp[4])
{
#if defined(MBEDTLS_SELF_TEST)
dbl_count++;
@@ -1511,63 +1501,60 @@ static int ecp_double_jac(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
#else
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
- mbedtls_mpi M, S, T, U;
-
- mbedtls_mpi_init(&M); mbedtls_mpi_init(&S); mbedtls_mpi_init(&T); mbedtls_mpi_init(&U);
/* Special case for A = -3 */
- if (grp->A.p == NULL) {
- /* M = 3(X + Z^2)(X - Z^2) */
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &S, &P->Z, &P->Z));
- MBEDTLS_MPI_CHK(mbedtls_mpi_add_mod(grp, &T, &P->X, &S));
- MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &U, &P->X, &S));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &S, &T, &U));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&M, &S, 3)); MOD_ADD(M);
+ if (mbedtls_ecp_group_a_is_minus_3(grp)) {
+ /* tmp[0] <- M = 3(X + Z^2)(X - Z^2) */
+ MPI_ECP_SQR(&tmp[1], &P->Z);
+ MPI_ECP_ADD(&tmp[2], &P->X, &tmp[1]);
+ MPI_ECP_SUB(&tmp[3], &P->X, &tmp[1]);
+ MPI_ECP_MUL(&tmp[1], &tmp[2], &tmp[3]);
+ MPI_ECP_MUL_INT(&tmp[0], &tmp[1], 3);
} else {
- /* M = 3.X^2 */
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &S, &P->X, &P->X));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&M, &S, 3)); MOD_ADD(M);
+ /* tmp[0] <- M = 3.X^2 + A.Z^4 */
+ MPI_ECP_SQR(&tmp[1], &P->X);
+ MPI_ECP_MUL_INT(&tmp[0], &tmp[1], 3);
/* Optimize away for "koblitz" curves with A = 0 */
- if (mbedtls_mpi_cmp_int(&grp->A, 0) != 0) {
+ if (MPI_ECP_CMP_INT(&grp->A, 0) != 0) {
/* M += A.Z^4 */
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &S, &P->Z, &P->Z));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T, &S, &S));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &S, &T, &grp->A));
- MBEDTLS_MPI_CHK(mbedtls_mpi_add_mod(grp, &M, &M, &S));
+ MPI_ECP_SQR(&tmp[1], &P->Z);
+ MPI_ECP_SQR(&tmp[2], &tmp[1]);
+ MPI_ECP_MUL(&tmp[1], &tmp[2], &grp->A);
+ MPI_ECP_ADD(&tmp[0], &tmp[0], &tmp[1]);
}
}
- /* S = 4.X.Y^2 */
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T, &P->Y, &P->Y));
- MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l_mod(grp, &T, 1));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &S, &P->X, &T));
- MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l_mod(grp, &S, 1));
+ /* tmp[1] <- S = 4.X.Y^2 */
+ MPI_ECP_SQR(&tmp[2], &P->Y);
+ MPI_ECP_SHIFT_L(&tmp[2], 1);
+ MPI_ECP_MUL(&tmp[1], &P->X, &tmp[2]);
+ MPI_ECP_SHIFT_L(&tmp[1], 1);
- /* U = 8.Y^4 */
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &U, &T, &T));
- MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l_mod(grp, &U, 1));
+ /* tmp[3] <- U = 8.Y^4 */
+ MPI_ECP_SQR(&tmp[3], &tmp[2]);
+ MPI_ECP_SHIFT_L(&tmp[3], 1);
- /* T = M^2 - 2.S */
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T, &M, &M));
- MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &T, &T, &S));
- MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &T, &T, &S));
+ /* tmp[2] <- T = M^2 - 2.S */
+ MPI_ECP_SQR(&tmp[2], &tmp[0]);
+ MPI_ECP_SUB(&tmp[2], &tmp[2], &tmp[1]);
+ MPI_ECP_SUB(&tmp[2], &tmp[2], &tmp[1]);
- /* S = M(S - T) - U */
- MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &S, &S, &T));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &S, &S, &M));
- MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &S, &S, &U));
+ /* tmp[1] <- S = M(S - T) - U */
+ MPI_ECP_SUB(&tmp[1], &tmp[1], &tmp[2]);
+ MPI_ECP_MUL(&tmp[1], &tmp[1], &tmp[0]);
+ MPI_ECP_SUB(&tmp[1], &tmp[1], &tmp[3]);
- /* U = 2.Y.Z */
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &U, &P->Y, &P->Z));
- MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l_mod(grp, &U, 1));
+ /* tmp[3] <- U = 2.Y.Z */
+ MPI_ECP_MUL(&tmp[3], &P->Y, &P->Z);
+ MPI_ECP_SHIFT_L(&tmp[3], 1);
- MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R->X, &T));
- MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R->Y, &S));
- MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R->Z, &U));
+ /* Store results */
+ MPI_ECP_MOV(&R->X, &tmp[2]);
+ MPI_ECP_MOV(&R->Y, &tmp[1]);
+ MPI_ECP_MOV(&R->Z, &tmp[3]);
cleanup:
- mbedtls_mpi_free(&M); mbedtls_mpi_free(&S); mbedtls_mpi_free(&T); mbedtls_mpi_free(&U);
return ret;
#endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || !defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) */
@@ -1579,6 +1566,10 @@ cleanup:
* The coordinates of Q must be normalized (= affine),
* but those of P don't need to. R is not normalized.
*
+ * P,Q,R may alias, but only at the level of EC points: they must be either
+ * equal as pointers, or disjoint (including the coordinate data buffers).
+ * Fine-grained aliasing at the level of coordinates is not supported.
+ *
* Special cases: (1) P or Q is zero, (2) R is zero, (3) P == Q.
* None of these cases can happen as intermediate step in ecp_mul_comb():
* - at each step, P, Q and R are multiples of the base point, the factor
@@ -1587,12 +1578,11 @@ cleanup:
* due to the choice of precomputed points in the modified comb method.
* So branches for these cases do not leak secret information.
*
- * We accept Q->Z being unset (saving memory in tables) as meaning 1.
- *
* Cost: 1A := 8M + 3S
*/
static int ecp_add_mixed(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
- const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q)
+ const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q,
+ mbedtls_mpi tmp[4])
{
#if defined(MBEDTLS_SELF_TEST)
add_count++;
@@ -1608,40 +1598,47 @@ static int ecp_add_mixed(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
#else
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
- mbedtls_mpi T1, T2, T3, T4, X, Y, Z;
+
+ /* NOTE: Aliasing between input and output is allowed, so one has to make
+ * sure that at the point X,Y,Z are written, {P,Q}->{X,Y,Z} are no
+ * longer read from. */
+ mbedtls_mpi * const X = &R->X;
+ mbedtls_mpi * const Y = &R->Y;
+ mbedtls_mpi * const Z = &R->Z;
+
+ if (!MPI_ECP_VALID(&Q->Z)) {
+ return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
+ }
/*
* Trivial cases: P == 0 or Q == 0 (case 1)
*/
- if (mbedtls_mpi_cmp_int(&P->Z, 0) == 0) {
+ if (MPI_ECP_CMP_INT(&P->Z, 0) == 0) {
return mbedtls_ecp_copy(R, Q);
}
- if (Q->Z.p != NULL && mbedtls_mpi_cmp_int(&Q->Z, 0) == 0) {
+ if (MPI_ECP_CMP_INT(&Q->Z, 0) == 0) {
return mbedtls_ecp_copy(R, P);
}
/*
* Make sure Q coordinates are normalized
*/
- if (Q->Z.p != NULL && mbedtls_mpi_cmp_int(&Q->Z, 1) != 0) {
+ if (MPI_ECP_CMP_INT(&Q->Z, 1) != 0) {
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
- mbedtls_mpi_init(&T1); mbedtls_mpi_init(&T2); mbedtls_mpi_init(&T3); mbedtls_mpi_init(&T4);
- mbedtls_mpi_init(&X); mbedtls_mpi_init(&Y); mbedtls_mpi_init(&Z);
-
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T1, &P->Z, &P->Z));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T2, &T1, &P->Z));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T1, &T1, &Q->X));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T2, &T2, &Q->Y));
- MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &T1, &T1, &P->X));
- MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &T2, &T2, &P->Y));
+ MPI_ECP_SQR(&tmp[0], &P->Z);
+ MPI_ECP_MUL(&tmp[1], &tmp[0], &P->Z);
+ MPI_ECP_MUL(&tmp[0], &tmp[0], &Q->X);
+ MPI_ECP_MUL(&tmp[1], &tmp[1], &Q->Y);
+ MPI_ECP_SUB(&tmp[0], &tmp[0], &P->X);
+ MPI_ECP_SUB(&tmp[1], &tmp[1], &P->Y);
/* Special cases (2) and (3) */
- if (mbedtls_mpi_cmp_int(&T1, 0) == 0) {
- if (mbedtls_mpi_cmp_int(&T2, 0) == 0) {
- ret = ecp_double_jac(grp, R, P);
+ if (MPI_ECP_CMP_INT(&tmp[0], 0) == 0) {
+ if (MPI_ECP_CMP_INT(&tmp[1], 0) == 0) {
+ ret = ecp_double_jac(grp, R, P, tmp);
goto cleanup;
} else {
ret = mbedtls_ecp_set_zero(R);
@@ -1649,28 +1646,26 @@ static int ecp_add_mixed(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
}
}
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &Z, &P->Z, &T1));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T3, &T1, &T1));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T4, &T3, &T1));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T3, &T3, &P->X));
- MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T1, &T3));
- MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l_mod(grp, &T1, 1));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &X, &T2, &T2));
- MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &X, &X, &T1));
- MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &X, &X, &T4));
- MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &T3, &T3, &X));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T3, &T3, &T2));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T4, &T4, &P->Y));
- MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &Y, &T3, &T4));
-
- MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R->X, &X));
- MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R->Y, &Y));
- MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R->Z, &Z));
+ /* {P,Q}->Z no longer used, so OK to write to Z even if there's aliasing. */
+ MPI_ECP_MUL(Z, &P->Z, &tmp[0]);
+ MPI_ECP_SQR(&tmp[2], &tmp[0]);
+ MPI_ECP_MUL(&tmp[3], &tmp[2], &tmp[0]);
+ MPI_ECP_MUL(&tmp[2], &tmp[2], &P->X);
-cleanup:
+ MPI_ECP_MOV(&tmp[0], &tmp[2]);
+ MPI_ECP_SHIFT_L(&tmp[0], 1);
+
+ /* {P,Q}->X no longer used, so OK to write to X even if there's aliasing. */
+ MPI_ECP_SQR(X, &tmp[1]);
+ MPI_ECP_SUB(X, X, &tmp[0]);
+ MPI_ECP_SUB(X, X, &tmp[3]);
+ MPI_ECP_SUB(&tmp[2], &tmp[2], X);
+ MPI_ECP_MUL(&tmp[2], &tmp[2], &tmp[1]);
+ MPI_ECP_MUL(&tmp[3], &tmp[3], &P->Y);
+ /* {P,Q}->Y no longer used, so OK to write to Y even if there's aliasing. */
+ MPI_ECP_SUB(Y, &tmp[2], &tmp[3]);
- mbedtls_mpi_free(&T1); mbedtls_mpi_free(&T2); mbedtls_mpi_free(&T3); mbedtls_mpi_free(&T4);
- mbedtls_mpi_free(&X); mbedtls_mpi_free(&Y); mbedtls_mpi_free(&Z);
+cleanup:
return ret;
#endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || !defined(MBEDTLS_ECP_ADD_MIXED_ALT) */
@@ -1696,26 +1691,28 @@ static int ecp_randomize_jac(const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt
return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
#else
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
- mbedtls_mpi l, ll;
+ mbedtls_mpi l;
- mbedtls_mpi_init(&l); mbedtls_mpi_init(&ll);
+ mbedtls_mpi_init(&l);
/* Generate l such that 1 < l < p */
- MBEDTLS_MPI_CHK(mbedtls_mpi_random(&l, 2, &grp->P, f_rng, p_rng));
+ MPI_ECP_RAND(&l);
- /* Z = l * Z */
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &pt->Z, &pt->Z, &l));
+ /* Z' = l * Z */
+ MPI_ECP_MUL(&pt->Z, &pt->Z, &l);
- /* X = l^2 * X */
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &ll, &l, &l));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &pt->X, &pt->X, &ll));
+ /* Y' = l * Y */
+ MPI_ECP_MUL(&pt->Y, &pt->Y, &l);
- /* Y = l^3 * Y */
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &ll, &ll, &l));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &pt->Y, &pt->Y, &ll));
+ /* X' = l^2 * X */
+ MPI_ECP_SQR(&l, &l);
+ MPI_ECP_MUL(&pt->X, &pt->X, &l);
+
+ /* Y'' = l^2 * Y' = l^3 * Y */
+ MPI_ECP_MUL(&pt->Y, &pt->Y, &l);
cleanup:
- mbedtls_mpi_free(&l); mbedtls_mpi_free(&ll);
+ mbedtls_mpi_free(&l);
if (ret == MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) {
ret = MBEDTLS_ERR_ECP_RANDOM_FAILED;
@@ -1858,7 +1855,11 @@ static int ecp_precompute_comb(const mbedtls_ecp_group *grp,
unsigned char i;
size_t j = 0;
const unsigned char T_size = 1U << (w - 1);
- mbedtls_ecp_point *cur, *TT[COMB_MAX_PRE - 1];
+ mbedtls_ecp_point *cur, *TT[COMB_MAX_PRE - 1] = { NULL };
+
+ mbedtls_mpi tmp[4];
+
+ mpi_init_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi));
#if defined(MBEDTLS_ECP_RESTARTABLE)
if (rs_ctx != NULL && rs_ctx->rsm != NULL) {
@@ -1912,7 +1913,7 @@ dbl:
MBEDTLS_MPI_CHK(mbedtls_ecp_copy(cur, T + (i >> 1)));
}
- MBEDTLS_MPI_CHK(ecp_double_jac(grp, cur, cur));
+ MBEDTLS_MPI_CHK(ecp_double_jac(grp, cur, cur, tmp));
}
#if defined(MBEDTLS_ECP_RESTARTABLE)
@@ -1923,8 +1924,11 @@ dbl:
norm_dbl:
#endif
/*
- * Normalize current elements in T. As T has holes,
- * use an auxiliary array of pointers to elements in T.
+ * Normalize current elements in T to allow them to be used in
+ * ecp_add_mixed() below, which requires one normalized input.
+ *
+ * As T has holes, use an auxiliary array of pointers to elements in T.
+ *
*/
j = 0;
for (i = 1; i < T_size; i <<= 1) {
@@ -1951,7 +1955,7 @@ add:
for (i = 1; i < T_size; i <<= 1) {
j = i;
while (j--) {
- MBEDTLS_MPI_CHK(ecp_add_mixed(grp, &T[i + j], &T[j], &T[i]));
+ MBEDTLS_MPI_CHK(ecp_add_mixed(grp, &T[i + j], &T[j], &T[i], tmp));
}
}
@@ -1975,7 +1979,19 @@ norm_add:
MBEDTLS_MPI_CHK(ecp_normalize_jac_many(grp, TT, j));
+ /* Free Z coordinate (=1 after normalization) to save RAM.
+ * This makes T[i] invalid as mbedtls_ecp_points, but this is OK
+ * since from this point onwards, they are only accessed indirectly
+ * via the getter function ecp_select_comb() which does set the
+ * target's Z coordinate to 1. */
+ for (i = 0; i < T_size; i++) {
+ mbedtls_mpi_free(&T[i].Z);
+ }
+
cleanup:
+
+ mpi_free_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi));
+
#if defined(MBEDTLS_ECP_RESTARTABLE)
if (rs_ctx != NULL && rs_ctx->rsm != NULL &&
ret == MBEDTLS_ERR_ECP_IN_PROGRESS) {
@@ -2005,13 +2021,15 @@ static int ecp_select_comb(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
/* Read the whole table to thwart cache-based timing attacks */
for (j = 0; j < T_size; j++) {
- MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign(&R->X, &T[j].X, j == ii));
- MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign(&R->Y, &T[j].Y, j == ii));
+ MPI_ECP_COND_ASSIGN(&R->X, &T[j].X, j == ii);
+ MPI_ECP_COND_ASSIGN(&R->Y, &T[j].Y, j == ii);
}
/* Safely invert result if i is "negative" */
MBEDTLS_MPI_CHK(ecp_safe_invert_jac(grp, R, i >> 7));
+ MPI_ECP_LSET(&R->Z, 1);
+
cleanup:
return ret;
}
@@ -2031,9 +2049,11 @@ static int ecp_mul_comb_core(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_ecp_point Txi;
+ mbedtls_mpi tmp[4];
size_t i;
mbedtls_ecp_point_init(&Txi);
+ mpi_init_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi));
#if !defined(MBEDTLS_ECP_RESTARTABLE)
(void) rs_ctx;
@@ -2053,19 +2073,10 @@ static int ecp_mul_comb_core(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
} else
#endif
{
- int have_rng = 1;
-
/* Start with a non-zero point and randomize its coordinates */
i = d;
MBEDTLS_MPI_CHK(ecp_select_comb(grp, R, T, T_size, x[i]));
- MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&R->Z, 1));
-
-#if defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
- if (f_rng == NULL) {
- have_rng = 0;
- }
-#endif
- if (have_rng) {
+ if (f_rng != 0) {
MBEDTLS_MPI_CHK(ecp_randomize_jac(grp, R, f_rng, p_rng));
}
}
@@ -2074,14 +2085,15 @@ static int ecp_mul_comb_core(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_DBL + MBEDTLS_ECP_OPS_ADD);
--i;
- MBEDTLS_MPI_CHK(ecp_double_jac(grp, R, R));
+ MBEDTLS_MPI_CHK(ecp_double_jac(grp, R, R, tmp));
MBEDTLS_MPI_CHK(ecp_select_comb(grp, &Txi, T, T_size, x[i]));
- MBEDTLS_MPI_CHK(ecp_add_mixed(grp, R, R, &Txi));
+ MBEDTLS_MPI_CHK(ecp_add_mixed(grp, R, R, &Txi, tmp));
}
cleanup:
mbedtls_ecp_point_free(&Txi);
+ mpi_free_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi));
#if defined(MBEDTLS_ECP_RESTARTABLE)
if (rs_ctx != NULL && rs_ctx->rsm != NULL &&
@@ -2164,7 +2176,6 @@ static int ecp_mul_comb_after_precomp(const mbedtls_ecp_group *grp,
unsigned char parity_trick;
unsigned char k[COMB_MAX_D + 1];
mbedtls_ecp_point *RR = R;
- int have_rng = 1;
#if defined(MBEDTLS_ECP_RESTARTABLE)
if (rs_ctx != NULL && rs_ctx->rsm != NULL) {
@@ -2201,12 +2212,7 @@ final_norm:
*
* Avoid the leak by randomizing coordinates before we normalize them.
*/
-#if defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
- if (f_rng == NULL) {
- have_rng = 0;
- }
-#endif
- if (have_rng) {
+ if (f_rng != 0) {
MBEDTLS_MPI_CHK(ecp_randomize_jac(grp, RR, f_rng, p_rng));
}
@@ -2247,11 +2253,16 @@ static unsigned char ecp_pick_window_size(const mbedtls_ecp_group *grp,
}
/*
- * Make sure w is within bounds.
+ * If static comb table may not be used (!p_eq_g) or static comb table does
+ * not exists, make sure w is within bounds.
* (The last test is useful only for very small curves in the test suite.)
+ *
+ * The user reduces MBEDTLS_ECP_WINDOW_SIZE does not changes the size of
+ * static comb table, because the size of static comb table is fixed when
+ * it is generated.
*/
#if (MBEDTLS_ECP_WINDOW_SIZE < 6)
- if (w > MBEDTLS_ECP_WINDOW_SIZE) {
+ if ((!p_eq_g || !ecp_group_is_static_comb_table(grp)) && w > MBEDTLS_ECP_WINDOW_SIZE) {
w = MBEDTLS_ECP_WINDOW_SIZE;
}
#endif
@@ -2286,46 +2297,13 @@ static int ecp_mul_comb(mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
size_t d;
unsigned char T_size = 0, T_ok = 0;
mbedtls_ecp_point *T = NULL;
-#if !defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
- ecp_drbg_context drbg_ctx;
-
- ecp_drbg_init(&drbg_ctx);
-#endif
ECP_RS_ENTER(rsm);
-#if !defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
- if (f_rng == NULL) {
- /* Adjust pointers */
- f_rng = &ecp_drbg_random;
-#if defined(MBEDTLS_ECP_RESTARTABLE)
- if (rs_ctx != NULL && rs_ctx->rsm != NULL) {
- p_rng = &rs_ctx->rsm->drbg_ctx;
- } else
-#endif
- p_rng = &drbg_ctx;
-
- /* Initialize internal DRBG if necessary */
-#if defined(MBEDTLS_ECP_RESTARTABLE)
- if (rs_ctx == NULL || rs_ctx->rsm == NULL ||
- rs_ctx->rsm->drbg_seeded == 0)
-#endif
- {
- const size_t m_len = (grp->nbits + 7) / 8;
- MBEDTLS_MPI_CHK(ecp_drbg_seed(p_rng, m, m_len));
- }
-#if defined(MBEDTLS_ECP_RESTARTABLE)
- if (rs_ctx != NULL && rs_ctx->rsm != NULL) {
- rs_ctx->rsm->drbg_seeded = 1;
- }
-#endif
- }
-#endif /* !MBEDTLS_ECP_NO_INTERNAL_RNG */
-
/* Is P the base point ? */
#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1
- p_eq_g = (mbedtls_mpi_cmp_mpi(&P->Y, &grp->G.Y) == 0 &&
- mbedtls_mpi_cmp_mpi(&P->X, &grp->G.X) == 0);
+ p_eq_g = (MPI_ECP_CMP(&P->Y, &grp->G.Y) == 0 &&
+ MPI_ECP_CMP(&P->X, &grp->G.X) == 0);
#else
p_eq_g = 0;
#endif
@@ -2387,10 +2365,6 @@ static int ecp_mul_comb(mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
cleanup:
-#if !defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
- ecp_drbg_free(&drbg_ctx);
-#endif
-
/* does T belong to the group? */
if (T == grp->T) {
T = NULL;
@@ -2458,9 +2432,9 @@ static int ecp_normalize_mxz(const mbedtls_ecp_group *grp, mbedtls_ecp_point *P)
return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
#else
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
- MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&P->Z, &P->Z, &grp->P));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &P->X, &P->X, &P->Z));
- MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&P->Z, 1));
+ MPI_ECP_INV(&P->Z, &P->Z);
+ MPI_ECP_MUL(&P->X, &P->X, &P->Z);
+ MPI_ECP_LSET(&P->Z, 1);
cleanup:
return ret;
@@ -2492,10 +2466,10 @@ static int ecp_randomize_mxz(const mbedtls_ecp_group *grp, mbedtls_ecp_point *P,
mbedtls_mpi_init(&l);
/* Generate l such that 1 < l < p */
- MBEDTLS_MPI_CHK(mbedtls_mpi_random(&l, 2, &grp->P, f_rng, p_rng));
+ MPI_ECP_RAND(&l);
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &P->X, &P->X, &l));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &P->Z, &P->Z, &l));
+ MPI_ECP_MUL(&P->X, &P->X, &l);
+ MPI_ECP_MUL(&P->Z, &P->Z, &l);
cleanup:
mbedtls_mpi_free(&l);
@@ -2525,7 +2499,8 @@ cleanup:
static int ecp_double_add_mxz(const mbedtls_ecp_group *grp,
mbedtls_ecp_point *R, mbedtls_ecp_point *S,
const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q,
- const mbedtls_mpi *d)
+ const mbedtls_mpi *d,
+ mbedtls_mpi T[4])
{
#if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT)
if (mbedtls_internal_ecp_grp_capable(grp)) {
@@ -2537,35 +2512,27 @@ static int ecp_double_add_mxz(const mbedtls_ecp_group *grp,
return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
#else
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
- mbedtls_mpi A, AA, B, BB, E, C, D, DA, CB;
-
- mbedtls_mpi_init(&A); mbedtls_mpi_init(&AA); mbedtls_mpi_init(&B);
- mbedtls_mpi_init(&BB); mbedtls_mpi_init(&E); mbedtls_mpi_init(&C);
- mbedtls_mpi_init(&D); mbedtls_mpi_init(&DA); mbedtls_mpi_init(&CB);
-
- MBEDTLS_MPI_CHK(mbedtls_mpi_add_mod(grp, &A, &P->X, &P->Z));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &AA, &A, &A));
- MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &B, &P->X, &P->Z));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &BB, &B, &B));
- MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &E, &AA, &BB));
- MBEDTLS_MPI_CHK(mbedtls_mpi_add_mod(grp, &C, &Q->X, &Q->Z));
- MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &D, &Q->X, &Q->Z));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &DA, &D, &A));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &CB, &C, &B));
- MBEDTLS_MPI_CHK(mbedtls_mpi_add_mod(grp, &S->X, &DA, &CB));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &S->X, &S->X, &S->X));
- MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &S->Z, &DA, &CB));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &S->Z, &S->Z, &S->Z));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &S->Z, d, &S->Z));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &R->X, &AA, &BB));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &R->Z, &grp->A, &E));
- MBEDTLS_MPI_CHK(mbedtls_mpi_add_mod(grp, &R->Z, &BB, &R->Z));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &R->Z, &E, &R->Z));
+
+ MPI_ECP_ADD(&T[0], &P->X, &P->Z); /* Pp := PX + PZ */
+ MPI_ECP_SUB(&T[1], &P->X, &P->Z); /* Pm := PX - PZ */
+ MPI_ECP_ADD(&T[2], &Q->X, &Q->Z); /* Qp := QX + XZ */
+ MPI_ECP_SUB(&T[3], &Q->X, &Q->Z); /* Qm := QX - QZ */
+ MPI_ECP_MUL(&T[3], &T[3], &T[0]); /* Qm * Pp */
+ MPI_ECP_MUL(&T[2], &T[2], &T[1]); /* Qp * Pm */
+ MPI_ECP_SQR(&T[0], &T[0]); /* Pp^2 */
+ MPI_ECP_SQR(&T[1], &T[1]); /* Pm^2 */
+ MPI_ECP_MUL(&R->X, &T[0], &T[1]); /* Pp^2 * Pm^2 */
+ MPI_ECP_SUB(&T[0], &T[0], &T[1]); /* Pp^2 - Pm^2 */
+ MPI_ECP_MUL(&R->Z, &grp->A, &T[0]); /* A * (Pp^2 - Pm^2) */
+ MPI_ECP_ADD(&R->Z, &T[1], &R->Z); /* [ A * (Pp^2-Pm^2) ] + Pm^2 */
+ MPI_ECP_ADD(&S->X, &T[3], &T[2]); /* Qm*Pp + Qp*Pm */
+ MPI_ECP_SQR(&S->X, &S->X); /* (Qm*Pp + Qp*Pm)^2 */
+ MPI_ECP_SUB(&S->Z, &T[3], &T[2]); /* Qm*Pp - Qp*Pm */
+ MPI_ECP_SQR(&S->Z, &S->Z); /* (Qm*Pp - Qp*Pm)^2 */
+ MPI_ECP_MUL(&S->Z, d, &S->Z); /* d * ( Qm*Pp - Qp*Pm )^2 */
+ MPI_ECP_MUL(&R->Z, &T[0], &R->Z); /* [A*(Pp^2-Pm^2)+Pm^2]*(Pp^2-Pm^2) */
cleanup:
- mbedtls_mpi_free(&A); mbedtls_mpi_free(&AA); mbedtls_mpi_free(&B);
- mbedtls_mpi_free(&BB); mbedtls_mpi_free(&E); mbedtls_mpi_free(&C);
- mbedtls_mpi_free(&D); mbedtls_mpi_free(&DA); mbedtls_mpi_free(&CB);
return ret;
#endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || !defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) */
@@ -2581,48 +2548,33 @@ static int ecp_mul_mxz(mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
void *p_rng)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
- int have_rng = 1;
size_t i;
unsigned char b;
mbedtls_ecp_point RP;
mbedtls_mpi PX;
-#if !defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
- ecp_drbg_context drbg_ctx;
-
- ecp_drbg_init(&drbg_ctx);
-#endif
+ mbedtls_mpi tmp[4];
mbedtls_ecp_point_init(&RP); mbedtls_mpi_init(&PX);
-#if !defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
+ mpi_init_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi));
+
if (f_rng == NULL) {
- const size_t m_len = (grp->nbits + 7) / 8;
- MBEDTLS_MPI_CHK(ecp_drbg_seed(&drbg_ctx, m, m_len));
- f_rng = &ecp_drbg_random;
- p_rng = &drbg_ctx;
+ return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
-#endif /* !MBEDTLS_ECP_NO_INTERNAL_RNG */
/* Save PX and read from P before writing to R, in case P == R */
- MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&PX, &P->X));
+ MPI_ECP_MOV(&PX, &P->X);
MBEDTLS_MPI_CHK(mbedtls_ecp_copy(&RP, P));
/* Set R to zero in modified x/z coordinates */
- MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&R->X, 1));
- MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&R->Z, 0));
+ MPI_ECP_LSET(&R->X, 1);
+ MPI_ECP_LSET(&R->Z, 0);
mbedtls_mpi_free(&R->Y);
/* RP.X might be slightly larger than P, so reduce it */
- MOD_ADD(RP.X);
+ MOD_ADD(&RP.X);
-#if defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
- /* Derandomize coordinates of the starting point */
- if (f_rng == NULL) {
- have_rng = 0;
- }
-#endif
- if (have_rng) {
- MBEDTLS_MPI_CHK(ecp_randomize_mxz(grp, &RP, f_rng, p_rng));
- }
+ /* Randomize coordinates of the starting point */
+ MBEDTLS_MPI_CHK(ecp_randomize_mxz(grp, &RP, f_rng, p_rng));
/* Loop invariant: R = result so far, RP = R + P */
i = grp->nbits + 1; /* one past the (zero-based) required msb for private keys */
@@ -2635,11 +2587,11 @@ static int ecp_mul_mxz(mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
* else double_add( R, RP, R, RP )
* but using safe conditional swaps to avoid leaks
*/
- MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_swap(&R->X, &RP.X, b));
- MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_swap(&R->Z, &RP.Z, b));
- MBEDTLS_MPI_CHK(ecp_double_add_mxz(grp, R, &RP, R, &RP, &PX));
- MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_swap(&R->X, &RP.X, b));
- MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_swap(&R->Z, &RP.Z, b));
+ MPI_ECP_COND_SWAP(&R->X, &RP.X, b);
+ MPI_ECP_COND_SWAP(&R->Z, &RP.Z, b);
+ MBEDTLS_MPI_CHK(ecp_double_add_mxz(grp, R, &RP, R, &RP, &PX, tmp));
+ MPI_ECP_COND_SWAP(&R->X, &RP.X, b);
+ MPI_ECP_COND_SWAP(&R->Z, &RP.Z, b);
}
/*
@@ -2653,25 +2605,13 @@ static int ecp_mul_mxz(mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
*
* Avoid the leak by randomizing coordinates before we normalize them.
*/
- have_rng = 1;
-#if defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
- if (f_rng == NULL) {
- have_rng = 0;
- }
-#endif
- if (have_rng) {
- MBEDTLS_MPI_CHK(ecp_randomize_mxz(grp, R, f_rng, p_rng));
- }
-
+ MBEDTLS_MPI_CHK(ecp_randomize_mxz(grp, R, f_rng, p_rng));
MBEDTLS_MPI_CHK(ecp_normalize_mxz(grp, R));
cleanup:
-#if !defined(MBEDTLS_ECP_NO_INTERNAL_RNG)
- ecp_drbg_free(&drbg_ctx);
-#endif
-
mbedtls_ecp_point_free(&RP); mbedtls_mpi_free(&PX);
+ mpi_free_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi));
return ret;
}
@@ -2679,20 +2619,19 @@ cleanup:
/*
* Restartable multiplication R = m * P
+ *
+ * This internal function can be called without an RNG in case where we know
+ * the inputs are not sensitive.
*/
-int mbedtls_ecp_mul_restartable(mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
- const mbedtls_mpi *m, const mbedtls_ecp_point *P,
- int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
- mbedtls_ecp_restart_ctx *rs_ctx)
+static int ecp_mul_restartable_internal(mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
+ const mbedtls_mpi *m, const mbedtls_ecp_point *P,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
+ mbedtls_ecp_restart_ctx *rs_ctx)
{
int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
#if defined(MBEDTLS_ECP_INTERNAL_ALT)
char is_grp_capable = 0;
#endif
- ECP_VALIDATE_RET(grp != NULL);
- ECP_VALIDATE_RET(R != NULL);
- ECP_VALIDATE_RET(m != NULL);
- ECP_VALIDATE_RET(P != NULL);
#if defined(MBEDTLS_ECP_RESTARTABLE)
/* reset ops count for this call if top-level */
@@ -2753,18 +2692,30 @@ cleanup:
}
/*
+ * Restartable multiplication R = m * P
+ */
+int mbedtls_ecp_mul_restartable(mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
+ const mbedtls_mpi *m, const mbedtls_ecp_point *P,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
+ mbedtls_ecp_restart_ctx *rs_ctx)
+{
+ if (f_rng == NULL) {
+ return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
+ }
+
+ return ecp_mul_restartable_internal(grp, R, m, P, f_rng, p_rng, rs_ctx);
+}
+
+/*
* Multiplication R = m * P
*/
int mbedtls_ecp_mul(mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
const mbedtls_mpi *m, const mbedtls_ecp_point *P,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
{
- ECP_VALIDATE_RET(grp != NULL);
- ECP_VALIDATE_RET(R != NULL);
- ECP_VALIDATE_RET(m != NULL);
- ECP_VALIDATE_RET(P != NULL);
return mbedtls_ecp_mul_restartable(grp, R, m, P, f_rng, p_rng, NULL);
}
+#endif /* MBEDTLS_ECP_C */
#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
/*
@@ -2788,22 +2739,12 @@ static int ecp_check_pubkey_sw(const mbedtls_ecp_group *grp, const mbedtls_ecp_p
/*
* YY = Y^2
- * RHS = X (X^2 + A) + B = X^3 + A X + B
+ * RHS = X^3 + A X + B
*/
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &YY, &pt->Y, &pt->Y));
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &RHS, &pt->X, &pt->X));
+ MPI_ECP_SQR(&YY, &pt->Y);
+ MBEDTLS_MPI_CHK(ecp_sw_rhs(grp, &RHS, &pt->X));
- /* Special case for A = -3 */
- if (grp->A.p == NULL) {
- MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&RHS, &RHS, 3)); MOD_SUB(RHS);
- } else {
- MBEDTLS_MPI_CHK(mbedtls_mpi_add_mod(grp, &RHS, &RHS, &grp->A));
- }
-
- MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &RHS, &RHS, &pt->X));
- MBEDTLS_MPI_CHK(mbedtls_mpi_add_mod(grp, &RHS, &RHS, &grp->B));
-
- if (mbedtls_mpi_cmp_mpi(&YY, &RHS) != 0) {
+ if (MPI_ECP_CMP(&YY, &RHS) != 0) {
ret = MBEDTLS_ERR_ECP_INVALID_KEY;
}
@@ -2815,6 +2756,7 @@ cleanup:
}
#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */
+#if defined(MBEDTLS_ECP_C)
#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
/*
* R = m * P with shortcuts for m == 0, m == 1 and m == -1
@@ -2827,6 +2769,8 @@ static int mbedtls_ecp_mul_shortcuts(mbedtls_ecp_group *grp,
mbedtls_ecp_restart_ctx *rs_ctx)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+ mbedtls_mpi tmp;
+ mbedtls_mpi_init(&tmp);
if (mbedtls_mpi_cmp_int(m, 0) == 0) {
MBEDTLS_MPI_CHK(mbedtls_ecp_check_pubkey(grp, P));
@@ -2837,15 +2781,15 @@ static int mbedtls_ecp_mul_shortcuts(mbedtls_ecp_group *grp,
} else if (mbedtls_mpi_cmp_int(m, -1) == 0) {
MBEDTLS_MPI_CHK(mbedtls_ecp_check_pubkey(grp, P));
MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, P));
- if (mbedtls_mpi_cmp_int(&R->Y, 0) != 0) {
- MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&R->Y, &grp->P, &R->Y));
- }
+ MPI_ECP_NEG(&R->Y);
} else {
- MBEDTLS_MPI_CHK(mbedtls_ecp_mul_restartable(grp, R, m, P,
- NULL, NULL, rs_ctx));
+ MBEDTLS_MPI_CHK(ecp_mul_restartable_internal(grp, R, m, P,
+ NULL, NULL, rs_ctx));
}
cleanup:
+ mbedtls_mpi_free(&tmp);
+
return ret;
}
@@ -2863,21 +2807,16 @@ int mbedtls_ecp_muladd_restartable(
mbedtls_ecp_point mP;
mbedtls_ecp_point *pmP = &mP;
mbedtls_ecp_point *pR = R;
+ mbedtls_mpi tmp[4];
#if defined(MBEDTLS_ECP_INTERNAL_ALT)
char is_grp_capable = 0;
#endif
- ECP_VALIDATE_RET(grp != NULL);
- ECP_VALIDATE_RET(R != NULL);
- ECP_VALIDATE_RET(m != NULL);
- ECP_VALIDATE_RET(P != NULL);
- ECP_VALIDATE_RET(n != NULL);
- ECP_VALIDATE_RET(Q != NULL);
-
if (mbedtls_ecp_get_type(grp) != MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) {
return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
}
mbedtls_ecp_point_init(&mP);
+ mpi_init_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi));
ECP_RS_ENTER(ma);
@@ -2924,7 +2863,7 @@ mul2:
add:
#endif
MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_ADD);
- MBEDTLS_MPI_CHK(ecp_add_mixed(grp, pR, pmP, pR));
+ MBEDTLS_MPI_CHK(ecp_add_mixed(grp, pR, pmP, pR, tmp));
#if defined(MBEDTLS_ECP_RESTARTABLE)
if (rs_ctx != NULL && rs_ctx->ma != NULL) {
rs_ctx->ma->state = ecp_rsma_norm;
@@ -2942,6 +2881,9 @@ norm:
#endif
cleanup:
+
+ mpi_free_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi));
+
#if defined(MBEDTLS_ECP_INTERNAL_ALT)
if (is_grp_capable) {
mbedtls_internal_ecp_free(grp);
@@ -2963,21 +2905,16 @@ int mbedtls_ecp_muladd(mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
const mbedtls_mpi *m, const mbedtls_ecp_point *P,
const mbedtls_mpi *n, const mbedtls_ecp_point *Q)
{
- ECP_VALIDATE_RET(grp != NULL);
- ECP_VALIDATE_RET(R != NULL);
- ECP_VALIDATE_RET(m != NULL);
- ECP_VALIDATE_RET(P != NULL);
- ECP_VALIDATE_RET(n != NULL);
- ECP_VALIDATE_RET(Q != NULL);
return mbedtls_ecp_muladd_restartable(grp, R, m, P, n, Q, NULL);
}
#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */
+#endif /* MBEDTLS_ECP_C */
#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED)
-#define ECP_MPI_INIT(s, n, p) { s, (n), (mbedtls_mpi_uint *) (p) }
+#define ECP_MPI_INIT(_p, _n) { .p = (mbedtls_mpi_uint *) (_p), .s = 1, .n = (_n) }
#define ECP_MPI_INIT_ARRAY(x) \
- ECP_MPI_INIT(1, sizeof(x) / sizeof(mbedtls_mpi_uint), x)
+ ECP_MPI_INIT(x, sizeof(x) / sizeof(mbedtls_mpi_uint))
/*
* Constants for the two points other than 0, 1, -1 (mod p) in
* https://cr.yp.to/ecdh.html#validate
@@ -3090,9 +3027,6 @@ static int ecp_check_pubkey_mx(const mbedtls_ecp_group *grp, const mbedtls_ecp_p
int mbedtls_ecp_check_pubkey(const mbedtls_ecp_group *grp,
const mbedtls_ecp_point *pt)
{
- ECP_VALIDATE_RET(grp != NULL);
- ECP_VALIDATE_RET(pt != NULL);
-
/* Must use affine coordinates */
if (mbedtls_mpi_cmp_int(&pt->Z, 1) != 0) {
return MBEDTLS_ERR_ECP_INVALID_KEY;
@@ -3117,9 +3051,6 @@ int mbedtls_ecp_check_pubkey(const mbedtls_ecp_group *grp,
int mbedtls_ecp_check_privkey(const mbedtls_ecp_group *grp,
const mbedtls_mpi *d)
{
- ECP_VALIDATE_RET(grp != NULL);
- ECP_VALIDATE_RET(d != NULL);
-
#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) {
/* see RFC 7748 sec. 5 para. 5 */
@@ -3208,10 +3139,6 @@ int mbedtls_ecp_gen_privkey(const mbedtls_ecp_group *grp,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng)
{
- ECP_VALIDATE_RET(grp != NULL);
- ECP_VALIDATE_RET(d != NULL);
- ECP_VALIDATE_RET(f_rng != NULL);
-
#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) {
return mbedtls_ecp_gen_privkey_mx(grp->nbits, d, f_rng, p_rng);
@@ -3227,6 +3154,7 @@ int mbedtls_ecp_gen_privkey(const mbedtls_ecp_group *grp,
return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
}
+#if defined(MBEDTLS_ECP_C)
/*
* Generate a keypair with configurable base point
*/
@@ -3237,12 +3165,6 @@ int mbedtls_ecp_gen_keypair_base(mbedtls_ecp_group *grp,
void *p_rng)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
- ECP_VALIDATE_RET(grp != NULL);
- ECP_VALIDATE_RET(d != NULL);
- ECP_VALIDATE_RET(G != NULL);
- ECP_VALIDATE_RET(Q != NULL);
- ECP_VALIDATE_RET(f_rng != NULL);
-
MBEDTLS_MPI_CHK(mbedtls_ecp_gen_privkey(grp, d, f_rng, p_rng));
MBEDTLS_MPI_CHK(mbedtls_ecp_mul(grp, Q, d, G, f_rng, p_rng));
@@ -3258,11 +3180,6 @@ int mbedtls_ecp_gen_keypair(mbedtls_ecp_group *grp,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng)
{
- ECP_VALIDATE_RET(grp != NULL);
- ECP_VALIDATE_RET(d != NULL);
- ECP_VALIDATE_RET(Q != NULL);
- ECP_VALIDATE_RET(f_rng != NULL);
-
return mbedtls_ecp_gen_keypair_base(grp, &grp->G, d, Q, f_rng, p_rng);
}
@@ -3273,17 +3190,35 @@ int mbedtls_ecp_gen_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
- ECP_VALIDATE_RET(key != NULL);
- ECP_VALIDATE_RET(f_rng != NULL);
-
if ((ret = mbedtls_ecp_group_load(&key->grp, grp_id)) != 0) {
return ret;
}
return mbedtls_ecp_gen_keypair(&key->grp, &key->d, &key->Q, f_rng, p_rng);
}
+#endif /* MBEDTLS_ECP_C */
+
+int mbedtls_ecp_set_public_key(mbedtls_ecp_group_id grp_id,
+ mbedtls_ecp_keypair *key,
+ const mbedtls_ecp_point *Q)
+{
+ int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+ if (key->grp.id == MBEDTLS_ECP_DP_NONE) {
+ /* Group not set yet */
+ if ((ret = mbedtls_ecp_group_load(&key->grp, grp_id)) != 0) {
+ return ret;
+ }
+ } else if (key->grp.id != grp_id) {
+ /* Group mismatch */
+ return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
+ }
+ return mbedtls_ecp_copy(&key->Q, Q);
+}
+
#define ECP_CURVE25519_KEY_SIZE 32
+#define ECP_CURVE448_KEY_SIZE 56
/*
* Read a private key.
*/
@@ -3292,9 +3227,6 @@ int mbedtls_ecp_read_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key,
{
int ret = 0;
- ECP_VALIDATE_RET(key != NULL);
- ECP_VALIDATE_RET(buf != NULL);
-
if ((ret = mbedtls_ecp_group_load(&key->grp, grp_id)) != 0) {
return ret;
}
@@ -3304,7 +3236,7 @@ int mbedtls_ecp_read_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key,
#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) {
/*
- * If it is Curve25519 curve then mask the key as mandated by RFC7748
+ * Mask the key as mandated by RFC7748 for Curve25519 and Curve448.
*/
if (grp_id == MBEDTLS_ECP_DP_CURVE25519) {
if (buflen != ECP_CURVE25519_KEY_SIZE) {
@@ -3329,20 +3261,35 @@ int mbedtls_ecp_read_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key,
mbedtls_mpi_set_bit(&key->d,
ECP_CURVE25519_KEY_SIZE * 8 - 2, 1)
);
- } else {
- ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
+ } else if (grp_id == MBEDTLS_ECP_DP_CURVE448) {
+ if (buflen != ECP_CURVE448_KEY_SIZE) {
+ return MBEDTLS_ERR_ECP_INVALID_KEY;
+ }
+
+ MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary_le(&key->d, buf, buflen));
+
+ /* Set the two least significant bits to 0 */
+ MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 0, 0));
+ MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 1, 0));
+
+ /* Set the most significant bit to 1 */
+ MBEDTLS_MPI_CHK(
+ mbedtls_mpi_set_bit(&key->d,
+ ECP_CURVE448_KEY_SIZE * 8 - 1, 1)
+ );
}
}
-
#endif
#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) {
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&key->d, buf, buflen));
+ }
+#endif
+ if (ret == 0) {
MBEDTLS_MPI_CHK(mbedtls_ecp_check_privkey(&key->grp, &key->d));
}
-#endif
cleanup:
if (ret != 0) {
@@ -3355,13 +3302,11 @@ cleanup:
/*
* Write a private key.
*/
+#if !defined MBEDTLS_DEPRECATED_REMOVED
int mbedtls_ecp_write_key(mbedtls_ecp_keypair *key,
unsigned char *buf, size_t buflen)
{
- int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
-
- ECP_VALIDATE_RET(key != NULL);
- ECP_VALIDATE_RET(buf != NULL);
+ int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) {
@@ -3370,12 +3315,13 @@ int mbedtls_ecp_write_key(mbedtls_ecp_keypair *key,
return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
}
- MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary_le(&key->d, buf, buflen));
- } else {
- ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
+ } else if (key->grp.id == MBEDTLS_ECP_DP_CURVE448) {
+ if (buflen < ECP_CURVE448_KEY_SIZE) {
+ return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
+ }
}
+ MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary_le(&key->d, buf, buflen));
}
-
#endif
#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) {
@@ -3387,19 +3333,63 @@ cleanup:
return ret;
}
+#endif /* MBEDTLS_DEPRECATED_REMOVED */
+
+int mbedtls_ecp_write_key_ext(const mbedtls_ecp_keypair *key,
+ size_t *olen, unsigned char *buf, size_t buflen)
+{
+ size_t len = (key->grp.nbits + 7) / 8;
+ if (len > buflen) {
+ /* For robustness, ensure *olen <= buflen even on error. */
+ *olen = 0;
+ return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
+ }
+ *olen = len;
+
+ /* Private key not set */
+ if (key->d.n == 0) {
+ return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
+ }
+
+#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
+ if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) {
+ return mbedtls_mpi_write_binary_le(&key->d, buf, len);
+ }
+#endif
+
+#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
+ if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) {
+ return mbedtls_mpi_write_binary(&key->d, buf, len);
+ }
+#endif
+
+ /* Private key set but no recognized curve type? This shouldn't happen. */
+ return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+}
+
+/*
+ * Write a public key.
+ */
+int mbedtls_ecp_write_public_key(const mbedtls_ecp_keypair *key,
+ int format, size_t *olen,
+ unsigned char *buf, size_t buflen)
+{
+ return mbedtls_ecp_point_write_binary(&key->grp, &key->Q,
+ format, olen, buf, buflen);
+}
+#if defined(MBEDTLS_ECP_C)
/*
* Check a public-private key pair
*/
-int mbedtls_ecp_check_pub_priv(const mbedtls_ecp_keypair *pub, const mbedtls_ecp_keypair *prv)
+int mbedtls_ecp_check_pub_priv(
+ const mbedtls_ecp_keypair *pub, const mbedtls_ecp_keypair *prv,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_ecp_point Q;
mbedtls_ecp_group grp;
- ECP_VALIDATE_RET(pub != NULL);
- ECP_VALIDATE_RET(prv != NULL);
-
if (pub->grp.id == MBEDTLS_ECP_DP_NONE ||
pub->grp.id != prv->grp.id ||
mbedtls_mpi_cmp_mpi(&pub->Q.X, &prv->Q.X) ||
@@ -3415,7 +3405,7 @@ int mbedtls_ecp_check_pub_priv(const mbedtls_ecp_keypair *pub, const mbedtls_ecp
mbedtls_ecp_group_copy(&grp, &prv->grp);
/* Also checks d is valid */
- MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&grp, &Q, &prv->d, &prv->grp.G, NULL, NULL));
+ MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&grp, &Q, &prv->d, &prv->grp.G, f_rng, p_rng));
if (mbedtls_mpi_cmp_mpi(&Q.X, &prv->Q.X) ||
mbedtls_mpi_cmp_mpi(&Q.Y, &prv->Q.Y) ||
@@ -3431,8 +3421,68 @@ cleanup:
return ret;
}
+int mbedtls_ecp_keypair_calc_public(mbedtls_ecp_keypair *key,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng)
+{
+ return mbedtls_ecp_mul(&key->grp, &key->Q, &key->d, &key->grp.G,
+ f_rng, p_rng);
+}
+#endif /* MBEDTLS_ECP_C */
+
+mbedtls_ecp_group_id mbedtls_ecp_keypair_get_group_id(
+ const mbedtls_ecp_keypair *key)
+{
+ return key->grp.id;
+}
+
+/*
+ * Export generic key-pair parameters.
+ */
+int mbedtls_ecp_export(const mbedtls_ecp_keypair *key, mbedtls_ecp_group *grp,
+ mbedtls_mpi *d, mbedtls_ecp_point *Q)
+{
+ int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+ if (grp != NULL && (ret = mbedtls_ecp_group_copy(grp, &key->grp)) != 0) {
+ return ret;
+ }
+
+ if (d != NULL && (ret = mbedtls_mpi_copy(d, &key->d)) != 0) {
+ return ret;
+ }
+
+ if (Q != NULL && (ret = mbedtls_ecp_copy(Q, &key->Q)) != 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
#if defined(MBEDTLS_SELF_TEST)
+#if defined(MBEDTLS_ECP_C)
+/*
+ * PRNG for test - !!!INSECURE NEVER USE IN PRODUCTION!!!
+ *
+ * This is the linear congruential generator from numerical recipes,
+ * except we only use the low byte as the output. See
+ * https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use
+ */
+static int self_test_rng(void *ctx, unsigned char *out, size_t len)
+{
+ static uint32_t state = 42;
+
+ (void) ctx;
+
+ for (size_t i = 0; i < len; i++) {
+ state = state * 1664525u + 1013904223u;
+ out[i] = (unsigned char) state;
+ }
+
+ return 0;
+}
+
/* Adjust the exponent to be a valid private point for the specified curve.
* This is sometimes necessary because we use a single set of exponents
* for all curves but the validity of values depends on the curve. */
@@ -3487,7 +3537,7 @@ static int self_test_point(int verbose,
MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(m, 16, exponents[0]));
MBEDTLS_MPI_CHK(self_test_adjust_exponent(grp, m));
- MBEDTLS_MPI_CHK(mbedtls_ecp_mul(grp, R, m, P, NULL, NULL));
+ MBEDTLS_MPI_CHK(mbedtls_ecp_mul(grp, R, m, P, self_test_rng, NULL));
for (i = 1; i < n_exponents; i++) {
add_c_prev = add_count;
@@ -3499,7 +3549,7 @@ static int self_test_point(int verbose,
MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(m, 16, exponents[i]));
MBEDTLS_MPI_CHK(self_test_adjust_exponent(grp, m));
- MBEDTLS_MPI_CHK(mbedtls_ecp_mul(grp, R, m, P, NULL, NULL));
+ MBEDTLS_MPI_CHK(mbedtls_ecp_mul(grp, R, m, P, self_test_rng, NULL));
if (add_count != add_c_prev ||
dbl_count != dbl_c_prev ||
@@ -3519,12 +3569,14 @@ cleanup:
}
return ret;
}
+#endif /* MBEDTLS_ECP_C */
/*
* Checkup routine
*/
int mbedtls_ecp_self_test(int verbose)
{
+#if defined(MBEDTLS_ECP_C)
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
mbedtls_ecp_group grp;
mbedtls_ecp_point R, P;
@@ -3577,7 +3629,7 @@ int mbedtls_ecp_self_test(int verbose)
}
/* Do a dummy multiplication first to trigger precomputation */
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&m, 2));
- MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&grp, &P, &m, &grp.G, NULL, NULL));
+ MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&grp, &P, &m, &grp.G, self_test_rng, NULL));
ret = self_test_point(verbose,
&grp, &R, &m, &grp.G,
sw_exponents,
@@ -3638,10 +3690,14 @@ cleanup:
}
return ret;
+#else /* MBEDTLS_ECP_C */
+ (void) verbose;
+ return 0;
+#endif /* MBEDTLS_ECP_C */
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* !MBEDTLS_ECP_ALT */
-#endif /* MBEDTLS_ECP_C */
+#endif /* MBEDTLS_ECP_LIGHT */