Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions tests/api/test_ecc.c
Original file line number Diff line number Diff line change
Expand Up @@ -3601,6 +3601,106 @@ int test_wc_ecc_mulmod(void)
return EXPECT_RESULT();
} /* END test_wc_ecc_mulmod */

/*
* Testing that wc_ecc_mulmod() of the private key and the base point gives
* the public key, on every curve compiled in. This covers curves the SP code
* implements and other curves of the same size, which must not be handed to
* the SP code.
*/
int test_wc_ecc_mulmod_curves(void)
{
EXPECT_DECLS;
#if defined(HAVE_ECC) && !defined(WC_NO_RNG) && \
!(defined(WOLFSSL_ATECC508A) || defined(WOLFSSL_ATECC608A) || \
defined(WOLFSSL_MICROCHIP_TA100) || \
defined(WOLFSSL_VALIDATE_ECC_IMPORT)) && \
!defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(HAVE_SELFTEST) && \
!defined(HAVE_FIPS) && \
!defined(WOLFSSL_NO_ECC_SW)
static const int curves[] = {
ECC_SECP256R1, ECC_SECP384R1, ECC_SECP521R1, ECC_SECP256K1,
ECC_BRAINPOOLP256R1, ECC_BRAINPOOLP384R1, ECC_BRAINPOOLP512R1
};
ecc_key key1;
ecc_key key2;
ecc_key key3;
ecc_key key4;
WC_RNG rng;
int ret;
int i;
int tested = 0;

XMEMSET(&rng, 0, sizeof(WC_RNG));
ExpectIntEQ(wc_InitRng(&rng), 0);

for (i = 0; i < (int)(sizeof(curves) / sizeof(curves[0])); i++) {
const ecc_set_type* dp;
int idx = wc_ecc_get_curve_idx(curves[i]);

if (idx < 0) {
continue;
}
dp = wc_ecc_get_curve_params(idx);
ExpectNotNull(dp);
if (dp == NULL) {
break;
}

XMEMSET(&key1, 0, sizeof(ecc_key));
XMEMSET(&key2, 0, sizeof(ecc_key));
XMEMSET(&key3, 0, sizeof(ecc_key));
XMEMSET(&key4, 0, sizeof(ecc_key));
ExpectIntEQ(wc_ecc_init(&key1), 0);
ExpectIntEQ(wc_ecc_init(&key2), 0);
ExpectIntEQ(wc_ecc_init(&key3), 0);
ExpectIntEQ(wc_ecc_init(&key4), 0);

ret = wc_ecc_make_key_ex(&rng, dp->size, &key1, curves[i]);
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &key1.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
ExpectIntEQ(ret, 0);

/* As in test_wc_ecc_mulmod(): the base point, the result point, and
* the curve parameter A and the prime as public coordinates. */
ExpectIntEQ(wc_ecc_import_raw_ex(&key2, dp->Gx, dp->Gy, NULL,
curves[i]), 0);
ExpectIntEQ(wc_ecc_import_raw_ex(&key3, dp->Gx, dp->Gy, NULL,
curves[i]), 0);
ExpectIntEQ(wc_ecc_import_raw_ex(&key4, dp->Af, dp->prime, NULL,
curves[i]), 0);

ExpectIntEQ(wc_ecc_mulmod(wc_ecc_key_get_priv(&key1), &key2.pubkey,
&key3.pubkey, key4.pubkey.x, key4.pubkey.y, 1), 0);
ExpectIntEQ(wc_ecc_cmp_point(&key3.pubkey, &key1.pubkey), MP_EQ);
#if defined(WOLFSSL_PUBLIC_MP) && !defined(WOLFSSL_SP_MATH)
/* The same base point with z = 1 + prime, a coordinate that is not
* reduced (and wider than the curve for most primes), must give the
* same result. WOLFSSL_SP_MATH builds reject coordinates wider than
* the curve instead. */
ExpectIntEQ(mp_add(key2.pubkey.z, key4.pubkey.y, key2.pubkey.z),
MP_OKAY);
ExpectIntEQ(wc_ecc_mulmod(wc_ecc_key_get_priv(&key1), &key2.pubkey,
&key3.pubkey, key4.pubkey.x, key4.pubkey.y, 1), 0);
ExpectIntEQ(wc_ecc_cmp_point(&key3.pubkey, &key1.pubkey), MP_EQ);
#endif
tested++;

wc_ecc_free(&key1);
wc_ecc_free(&key2);
wc_ecc_free(&key3);
wc_ecc_free(&key4);
}
ExpectIntGT(tested, 0);

DoExpectIntEQ(wc_FreeRng(&rng), 0);
#ifdef FP_ECC
wc_ecc_fp_free();
#endif
#endif
return EXPECT_RESULT();
} /* END test_wc_ecc_mulmod_curves */

/*
* Testing wc_ecc_mulmod() with base point ordinates that are not reduced
* modulo the prime.
Expand Down
2 changes: 2 additions & 0 deletions tests/api/test_ecc.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ int test_wc_ecc_pointFns(void);
int test_wc_ecc_shared_secret_ssh(void);
int test_wc_ecc_verify_hash_ex(void);
int test_wc_ecc_mulmod(void);
int test_wc_ecc_mulmod_curves(void);
int test_wc_ecc_mulmod_unreduced(void);
int test_wc_ecc_is_valid_idx(void);
int test_wc_ecc_get_curve_id_from_oid(void);
Expand Down Expand Up @@ -132,6 +133,7 @@ int test_wc_ecc_make_key_id_dev(void);
TEST_DECL_GROUP("ecc", test_wc_ecc_shared_secret_ssh), \
TEST_DECL_GROUP("ecc", test_wc_ecc_verify_hash_ex), \
TEST_DECL_GROUP("ecc", test_wc_ecc_mulmod), \
TEST_DECL_GROUP("ecc", test_wc_ecc_mulmod_curves), \
TEST_DECL_GROUP("ecc", test_wc_ecc_mulmod_unreduced), \
TEST_DECL_GROUP("ecc", test_wc_ecc_is_valid_idx), \
TEST_DECL_GROUP("ecc", test_wc_ecc_get_curve_id_from_oid), \
Expand Down
109 changes: 109 additions & 0 deletions wolfcrypt/src/ecc.c
Original file line number Diff line number Diff line change
Expand Up @@ -3808,6 +3808,108 @@ static void ecc_key_tmp_final(ecc_key* key, void* heap)
#endif /* WOLFSSL_SMALL_STACK_CACHE */
#endif /* !WOLFSSL_SP_MATH */

#if defined(WOLFSSL_HAVE_SP_ECC) && !defined(WOLFSSL_SP_MATH)
/* Point multiplication with the SP code for callers of wc_ecc_mulmod() and
* wc_ecc_mulmod_ex() (hostapd's SAE, for example) when the curve is one the SP
* code implements. Only the modulus and a are given, so the curve is
* identified by both, as other curves of the same size may be compiled in.
* Only when mapping back to affine coordinates, as otherwise the result is
* expected in the generic code's representation.
*
* Returns NOT_COMPILED_IN when the SP code does not apply.
*/
static int ecc_sp_mulmod(const mp_int* k, ecc_point* G, ecc_point* R,
mp_int* a, mp_int* modulus, int map, void* heap)
{
DECL_MP_INT_SIZE_DYN(t, mp_bitsused(modulus), MAX_ECC_BITS_USE);
int bits = mp_count_bits(modulus);
int curveId;
int idx;
int err;

if (!map || a == NULL || MP_BITS_OVER_MAX(bits, MAX_ECC_BITS_USE)) {
return NOT_COMPILED_IN;
}
switch (bits) {
#ifndef WOLFSSL_SP_NO_256
case 256:
curveId = ECC_SECP256R1;
break;
#endif
#ifdef WOLFSSL_SP_384
case 384:
curveId = ECC_SECP384R1;
break;
#endif
#ifdef WOLFSSL_SP_521
case 521:
curveId = ECC_SECP521R1;
break;
#endif
default:
return NOT_COMPILED_IN;
}
/* The SP code takes a non-negative scalar no longer than the curve and
* coordinates already reduced modulo the prime; it would truncate wider
* values. Leave anything else to the generic code, which reduces them. */
if (mp_isneg(k) || (mp_count_bits(k) > bits)) {
return NOT_COMPILED_IN;
}
if (mp_isneg(G->x) || mp_isneg(G->y) || mp_isneg(G->z) ||
(mp_cmp(G->x, modulus) != MP_LT) ||
(mp_cmp(G->y, modulus) != MP_LT) ||
(mp_cmp(G->z, modulus) != MP_LT)) {
return NOT_COMPILED_IN;
}
idx = wc_ecc_get_curve_idx(curveId);
if (idx < 0) {
return NOT_COMPILED_IN;
}

NEW_MP_INT_SIZE(t, bits, heap, DYNAMIC_TYPE_ECC);
#ifdef MP_INT_SIZE_CHECK_NULL
if (t == NULL) {
return MEMORY_E;
}
#endif
err = INIT_MP_INT_SIZE(t, bits);
if (err == MP_OKAY) {
err = mp_read_radix(t, ecc_sets[idx].prime, MP_RADIX_HEX);
}
if ((err == MP_OKAY) && (mp_cmp(t, modulus) != MP_EQ)) {
err = NOT_COMPILED_IN;
}
if (err == MP_OKAY) {
err = mp_read_radix(t, ecc_sets[idx].Af, MP_RADIX_HEX);
}
if ((err == MP_OKAY) && (mp_cmp(t, a) != MP_EQ)) {
err = NOT_COMPILED_IN;
}
mp_clear(t);
FREE_MP_INT_SIZE(t, heap, DYNAMIC_TYPE_ECC);
if (err != MP_OKAY) {
return err;
}

switch (bits) {
#ifndef WOLFSSL_SP_NO_256
case 256:
Comment thread
LinuxJedi marked this conversation as resolved.
Resolved
return sp_ecc_mulmod_256(k, G, R, map, heap);
Comment thread
LinuxJedi marked this conversation as resolved.
Resolved
#endif
#ifdef WOLFSSL_SP_384
case 384:
return sp_ecc_mulmod_384(k, G, R, map, heap);
#endif
#ifdef WOLFSSL_SP_521
case 521:
return sp_ecc_mulmod_521(k, G, R, map, heap);
#endif
default:
return NOT_COMPILED_IN;
}
}
#endif /* WOLFSSL_HAVE_SP_ECC && !WOLFSSL_SP_MATH */

#if !defined(WOLFSSL_SP_MATH) || !defined(FP_ECC)
/**
Perform a point multiplication
Expand Down Expand Up @@ -3855,6 +3957,13 @@ int wc_ecc_mulmod_ex(const mp_int* k, ecc_point *G, ecc_point *R, mp_int* a,
goto exit;
}

#if defined(WOLFSSL_HAVE_SP_ECC) && !defined(WOLFSSL_SP_MATH)
err = ecc_sp_mulmod(k, G, R, a, modulus, map, heap);
Comment thread
LinuxJedi marked this conversation as resolved.
Resolved
if (err != WC_NO_ERR_TRACE(NOT_COMPILED_IN)) {
return err;
}
#endif

#ifdef WOLFSSL_SMALL_STACK_CACHE
key = (ecc_key *)XMALLOC(sizeof(*key), heap, DYNAMIC_TYPE_ECC);
if (key == NULL) {
Expand Down
Loading