diff --git a/tests/api/test_ecc.c b/tests/api/test_ecc.c index 85f125c2e6b..cb785284df2 100644 --- a/tests/api/test_ecc.c +++ b/tests/api/test_ecc.c @@ -1172,6 +1172,214 @@ int test_wc_ecc_import_x963(void) return EXPECT_RESULT(); } /* END wc_ecc_import_x963 */ +#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_IMPORT) && \ + defined(HAVE_ECC_KEY_EXPORT) && defined(HAVE_COMP_KEY) && \ + !defined(WC_NO_RNG) && !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ + !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLFSSL_NO_ECC_SW) && \ + !defined(NO_ECC_SECP) && \ + (((!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \ + ECC_MIN_KEY_SZ <= 256) || \ + ((defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && \ + ECC_MIN_KEY_SZ <= 384) || \ + ((defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && \ + ECC_MIN_KEY_SZ <= 521)) +/* Import a compressed x ordinate that no point on the curve has through the + * trusted importer and expect it to be refused, import an x whose right-hand + * side sits on a reduction boundary of the SP Montgomery arithmetic and expect + * it to be accepted, then round trip a generated key through the same importer + * to show a valid compressed point still decompresses to the right y. */ +static int test_ecc_import_compressed_no_root(int curveId, const byte* noRoot, + word32 noRootSz, const byte* boundary, word32 boundarySz) +{ + EXPECT_DECLS; + ecc_key key; + ecc_point* pt = NULL; + WC_RNG rng; + byte out[ECC_ASN963_MAX_BUF_SZ]; + word32 outLen = (word32)sizeof(out); + int idx = wc_ecc_get_curve_idx(curveId); + int ret; + + XMEMSET(&key, 0, sizeof(key)); + XMEMSET(&rng, 0, sizeof(rng)); + ExpectIntNE(idx, ECC_CURVE_INVALID); + ExpectNotNull(pt = wc_ecc_new_point()); + + ExpectIntEQ(wc_ecc_import_point_der_ex(noRoot, noRootSz, idx, pt, 0), + WC_NO_ERR_TRACE(MP_VAL)); + if (boundary != NULL) { + ExpectIntEQ(wc_ecc_import_point_der_ex(boundary, boundarySz, idx, pt, + 0), 0); + } + + ExpectIntEQ(wc_ecc_init(&key), 0); + ExpectIntEQ(wc_InitRng(&rng), 0); + ret = wc_ecc_make_key_ex(&rng, 0, &key, curveId); +#if defined(WOLFSSL_ASYNC_CRYPT) + ret = wc_AsyncWait(ret, &key.asyncDev, WC_ASYNC_FLAG_NONE); +#endif + ExpectIntEQ(ret, 0); + PRIVATE_KEY_UNLOCK(); + ExpectIntEQ(wc_ecc_export_x963_ex(&key, out, &outLen, 1), 0); + PRIVATE_KEY_LOCK(); + ExpectIntEQ(wc_ecc_import_point_der_ex(out, outLen, idx, pt, 0), 0); + ExpectIntEQ(wc_ecc_cmp_point(&key.pubkey, pt), MP_EQ); + + DoExpectIntEQ(wc_FreeRng(&rng), 0); + wc_ecc_free(&key); + wc_ecc_del_point(pt); + + return EXPECT_RESULT(); +} +#endif + +/* + * testing compressed point import on each class of field prime: P-224 + * (p = 1 mod 8) and secp224k1 (p = 5 mod 8) decompress to the generator's y, + * and an x ordinate with no square root is refused on P-256, P-384 and P-521. + */ +int test_wc_ecc_import_compressed_sqrt(void) +{ + EXPECT_DECLS; +#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_IMPORT) && \ + defined(HAVE_ECC_KEY_EXPORT) && defined(HAVE_COMP_KEY) && \ + !defined(WC_NO_RNG) && !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) && \ + !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLFSSL_NO_ECC_SW) && \ + !defined(NO_ECC_SECP) +#if (defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)) && \ + ECC_MIN_KEY_SZ <= 224 && !defined(WOLFSSL_SP_MATH) +#ifndef SQRTMOD_USE_MOD_EXP + /* 02 || Gx of P-224 and the expected Gy. The single exponentiation + * square root does not support this prime (1 mod 8). */ + static const byte p224G[] = { + 0x02, 0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, 0x32, 0x13, + 0x90, 0xb9, 0x4a, 0x03, 0xc1, 0xd3, 0x56, 0xc2, 0x11, 0x22, 0x34, + 0x32, 0x80, 0xd6, 0x11, 0x5c, 0x1d, 0x21 + }; + static const byte p224Gy[] = { + 0xbd, 0x37, 0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb, 0x4c, 0x22, 0xdf, + 0xe6, 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07, 0x47, 0x64, 0x44, 0xd5, + 0x81, 0x99, 0x85, 0x00, 0x7e, 0x34 + }; +#endif +#if defined(HAVE_ECC_KOBLITZ) && !defined(FP_ECC) + /* 03 || Gx of secp224k1 and the expected Gy. */ + static const byte k224G[] = { + 0x03, 0xa1, 0x45, 0x5b, 0x33, 0x4d, 0xf0, 0x99, 0xdf, 0x30, 0xfc, + 0x28, 0xa1, 0x69, 0xa4, 0x67, 0xe9, 0xe4, 0x70, 0x75, 0xa9, 0x0f, + 0x7e, 0x65, 0x0e, 0xb6, 0xb7, 0xa4, 0x5c + }; + static const byte k224Gy[] = { + 0x7e, 0x08, 0x9f, 0xed, 0x7f, 0xba, 0x34, 0x42, 0x82, 0xca, 0xfb, + 0xd6, 0xf7, 0xe3, 0x19, 0xf7, 0xc0, 0xb0, 0xbd, 0x59, 0xe2, 0xca, + 0x4b, 0xdb, 0x55, 0x6d, 0x61, 0xa5 + }; +#endif +#if !defined(SQRTMOD_USE_MOD_EXP) || \ + (defined(HAVE_ECC_KOBLITZ) && !defined(FP_ECC)) + ecc_key key; + byte out[ECC_ASN963_MAX_BUF_SZ]; + word32 outLen; +#endif +#endif +#if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 256 + /* 02 || x with x^3 - 3x + b congruent to R^-1 mod p, so its Montgomery + * form is 1 and a non-canonical helper may hold it as p + 1. */ + static const byte p256Boundary[] = { + 0x02, 0xa0, 0x4a, 0x5c, 0xf3, 0x2f, 0x3a, 0x01, 0xbc, 0x8a, 0xba, + 0x5d, 0x63, 0xfa, 0x20, 0x7c, 0x70, 0x53, 0xaf, 0xd9, 0xf4, 0x9c, + 0xa1, 0x01, 0xc8, 0x19, 0x24, 0xc5, 0x74, 0xf5, 0x3c, 0x1e, 0x49 + }; + /* 02 || x with x = 1: x^3 - 3x + b has no square root mod p. */ + static const byte p256NoRoot[] = { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + }; +#endif +#if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384 + /* 02 || x with x = 1. */ + static const byte p384NoRoot[] = { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01 + }; +#endif +#if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 521 + /* 02 || x with x = 0x5701500: the square of the recovered y carries an + * unpropagated limb in the 32-bit SP arithmetic. */ + static const byte p521Boundary[] = { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x70, 0x15, + 0x00 + }; + /* 02 || x with x = 3. */ + static const byte p521NoRoot[] = { + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03 + }; +#endif + +#if (defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)) && \ + ECC_MIN_KEY_SZ <= 224 && !defined(WOLFSSL_SP_MATH) +#ifndef SQRTMOD_USE_MOD_EXP + XMEMSET(&key, 0, sizeof(key)); + ExpectIntEQ(wc_ecc_init(&key), 0); + ExpectIntEQ(wc_ecc_import_x963_ex(p224G, (word32)sizeof(p224G), &key, + ECC_SECP224R1), 0); + outLen = (word32)sizeof(out); + ExpectIntEQ(wc_ecc_export_x963(&key, out, &outLen), 0); + ExpectIntEQ(outLen, 1 + 2 * (word32)sizeof(p224Gy)); + ExpectBufEQ(out + 1 + sizeof(p224Gy), p224Gy, sizeof(p224Gy)); + wc_ecc_free(&key); +#endif + +#if defined(HAVE_ECC_KOBLITZ) && !defined(FP_ECC) + XMEMSET(&key, 0, sizeof(key)); + ExpectIntEQ(wc_ecc_init(&key), 0); + ExpectIntEQ(wc_ecc_import_x963_ex(k224G, (word32)sizeof(k224G), &key, + ECC_SECP224K1), 0); + outLen = (word32)sizeof(out); + ExpectIntEQ(wc_ecc_export_x963(&key, out, &outLen), 0); + ExpectIntEQ(outLen, 1 + 2 * (word32)sizeof(k224Gy)); + ExpectBufEQ(out + 1 + sizeof(k224Gy), k224Gy, sizeof(k224Gy)); + wc_ecc_free(&key); +#endif +#endif + +#if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 256 + ExpectIntEQ(test_ecc_import_compressed_no_root(ECC_SECP256R1, p256NoRoot, + (word32)sizeof(p256NoRoot), p256Boundary, (word32)sizeof(p256Boundary)), + TEST_SUCCESS); +#endif +#if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384 + ExpectIntEQ(test_ecc_import_compressed_no_root(ECC_SECP384R1, p384NoRoot, + (word32)sizeof(p384NoRoot), NULL, 0), TEST_SUCCESS); +#endif +#if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 521 + ExpectIntEQ(test_ecc_import_compressed_no_root(ECC_SECP521R1, p521NoRoot, + (word32)sizeof(p521NoRoot), p521Boundary, (word32)sizeof(p521Boundary)), + TEST_SUCCESS); +#endif + +#ifdef FP_ECC + wc_ecc_fp_free(); +#endif +#endif + return EXPECT_RESULT(); +} /* END test_wc_ecc_import_compressed_sqrt */ + /* * testing wc_ecc_import_x963() rejects an off-curve public point. * diff --git a/tests/api/test_ecc.h b/tests/api/test_ecc.h index 45258274c98..4efae60421e 100644 --- a/tests/api/test_ecc.h +++ b/tests/api/test_ecc.h @@ -43,6 +43,7 @@ int test_wc_ecc_shared_secret_size_bounds(void); int test_wc_ecc_export_x963(void); int test_wc_ecc_export_x963_ex(void); int test_wc_ecc_import_x963(void); +int test_wc_ecc_import_compressed_sqrt(void); int test_wc_ecc_import_x963_off_curve(void); int test_wc_ecc_import_x963_oversized(void); int test_wc_ecc_import_x963_non_canonical(void); @@ -106,6 +107,7 @@ int test_wc_ecc_make_key_id_dev(void); TEST_DECL_GROUP("ecc", test_wc_ecc_export_x963), \ TEST_DECL_GROUP("ecc", test_wc_ecc_export_x963_ex), \ TEST_DECL_GROUP("ecc", test_wc_ecc_import_x963), \ + TEST_DECL_GROUP("ecc", test_wc_ecc_import_compressed_sqrt), \ TEST_DECL_GROUP("ecc", test_wc_ecc_import_x963_off_curve), \ TEST_DECL_GROUP("ecc", test_wc_ecc_import_x963_oversized), \ TEST_DECL_GROUP("ecc", test_wc_ecc_import_x963_non_canonical), \ diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 14dc753ca48..3fe412f914d 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -129,9 +129,12 @@ Possible ECC enable options: * Auto-enabled unless using hardware accelerators. * WOLFSSL_PUBLIC_ECC_ADD_DBL: Makes ecc_projective_add_point default: off * and ecc_projective_dbl_point public APIs. - * SQRTMOD_USE_MOD_EXP: Computes square root mod prime using default: off - * modular exponentiation instead of Jacobi method - * for compressed key decompression. + * SQRTMOD_USE_MOD_EXP: Computes square root mod prime with a default: off + * single modular exponentiation, using less + * stack than Tonelli-Shanks. Primes that are + * 1 mod 8 (P-224) are not supported, and + * 5 mod 8 (secp224k1) only with + * HAVE_ECC_KOBLITZ or WOLFSSL_CUSTOM_CURVES. * * ECIES options: * WOLFSSL_ECIES_OLD: Uses original wolfSSL ECIES format default: off @@ -17035,48 +17038,134 @@ static int mp_jacobi(mp_int* a, mp_int* n, int* c) * The result is returned in the third argument x * the function returns MP_OKAY on success, MP_VAL or another error on failure */ +#if defined(SQRTMOD_USE_MOD_EXP) +/* Temporaries of the single exponentiation square root: the p = 5 mod 8 + * method needs one more. */ +#if defined(HAVE_ECC_KOBLITZ) || defined(WOLFSSL_CUSTOM_CURVES) + #define SQRTMOD_MOD_EXP_TMP_CNT 4 +#else + #define SQRTMOD_MOD_EXP_TMP_CNT 3 +#endif +#endif static int mp_sqrtmod_prime(mp_int* n, mp_int* prime, mp_int* ret) { #if defined(SQRTMOD_USE_MOD_EXP) + /* One modular exponentiation: n^((p+1)/4) for p = 3 mod 4 (HAC 3.36) and, + * only when a curve with such a prime can be present, Atkin's method for + * p = 5 mod 8. A prime that is 1 mod 8 has no single exponent square root + * and is refused. Three or four temporaries instead of the ten + * Tonelli-Shanks needs, which matters to callers on a small thread stack. */ int res; mp_digit i; - mp_int e; +#ifdef WOLFSSL_SMALL_STACK + mp_int* t = (mp_int*)XMALLOC(SQRTMOD_MOD_EXP_TMP_CNT * sizeof(mp_int), NULL, + DYNAMIC_TYPE_ECC_BUFFER); +#else + mp_int t[SQRTMOD_MOD_EXP_TMP_CNT]; +#endif + mp_int* N; + mp_int* e; + mp_int* c; +#if defined(HAVE_ECC_KOBLITZ) || defined(WOLFSSL_CUSTOM_CURVES) + mp_int* v; +#endif - /* first handle the simple cases n = 0 or n = 1 */ - if (mp_cmp_d(n, 0) == MP_EQ) { - mp_zero(ret); - return MP_OKAY; +#ifdef WOLFSSL_SMALL_STACK + if (t == NULL) { + return MEMORY_E; } - if (mp_cmp_d(n, 1) == MP_EQ) { - return mp_set(ret, 1); +#endif + N = &t[0]; + e = &t[1]; + c = &t[2]; +#if defined(HAVE_ECC_KOBLITZ) || defined(WOLFSSL_CUSTOM_CURVES) + v = &t[3]; + + res = mp_init_multi(N, e, c, v, NULL, NULL); +#else + res = mp_init_multi(N, e, c, NULL, NULL, NULL); +#endif + if (res != MP_OKAY) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(t, NULL, DYNAMIC_TYPE_ECC_BUFFER); + #endif + return res; } if (mp_iseven(prime)) { - return MP_VAL; + res = MP_VAL; + goto out; + } + res = mp_mod_d(prime, 8, &i); + if (res == MP_OKAY && i == 1) { + res = MP_VAL; } +#if !defined(HAVE_ECC_KOBLITZ) && !defined(WOLFSSL_CUSTOM_CURVES) + /* secp224k1 is the only built-in curve with a prime that is 5 mod 8. */ + if (res == MP_OKAY && i == 5) { + res = MP_VAL; + } +#endif - res = mp_init(&e); + /* reduce n to less than prime */ if (res == MP_OKAY) - res = mp_mod_d(prime, 8, &i); - if (res == MP_OKAY && i == 1) { - return MP_VAL; + res = mp_mod(n, prime, N); + /* when N is zero, sqrt is zero */ + if (res == MP_OKAY && mp_iszero(N)) { + mp_zero(ret); + goto out; } - /* prime mod 8 = 5 */ - else if (res == MP_OKAY && i == 5) { - res = mp_sub_d(prime, 1, &e); + +#if defined(HAVE_ECC_KOBLITZ) || defined(WOLFSSL_CUSTOM_CURVES) + /* prime mod 8 = 5: v = (2N)^((p-5)/8), i = 2N.v^2, ret = N.v.(i-1) */ + if (res == MP_OKAY && i == 5) { + res = mp_addmod(N, N, prime, c); + if (res == MP_OKAY) + res = mp_sub_d(prime, 5, e); + if (res == MP_OKAY) + res = mp_div_2d(e, 3, e, NULL); + if (res == MP_OKAY) + res = mp_exptmod(c, e, prime, v); if (res == MP_OKAY) - res = mp_div_2d(&e, 2, &e, NULL); + res = mp_sqrmod(v, prime, ret); + if (res == MP_OKAY) + res = mp_mulmod(ret, c, prime, ret); + if (res == MP_OKAY) + res = mp_sub_d(ret, 1, ret); + if (res == MP_OKAY) + res = mp_mulmod(ret, v, prime, ret); + if (res == MP_OKAY) + res = mp_mulmod(ret, N, prime, ret); } - /* prime mod 4 = 3 */ - else if (res == MP_OKAY && ((i == 3) || (i == 7))) { - res = mp_add_d(prime, 1, &e); + else +#endif + /* prime mod 4 = 3: ret = N^((p+1)/4) */ + if (res == MP_OKAY) { + res = mp_add_d(prime, 1, e); + if (res == MP_OKAY) + res = mp_div_2d(e, 2, e, NULL); if (res == MP_OKAY) - res = mp_div_2d(&e, 2, &e, NULL); + res = mp_exptmod(N, e, prime, ret); } + + /* Both formulas return a value for a non-residue too; only a value that + * squares back to N is a root. */ if (res == MP_OKAY) - res = mp_exptmod(n, &e, prime, ret); + res = mp_sqrmod(ret, prime, c); + if (res == MP_OKAY && mp_cmp(c, N) != MP_EQ) { + res = MP_VAL; + } - mp_clear(&e); +out: + mp_clear(N); + mp_clear(e); + mp_clear(c); +#if defined(HAVE_ECC_KOBLITZ) || defined(WOLFSSL_CUSTOM_CURVES) + mp_clear(v); +#endif +#ifdef WOLFSSL_SMALL_STACK + XFREE(t, NULL, DYNAMIC_TYPE_ECC_BUFFER); +#endif return res; #else diff --git a/wolfcrypt/src/sp_arm32.c b/wolfcrypt/src/sp_arm32.c index 7b19fdaec85..19f3bb27f2c 100644 --- a/wolfcrypt/src/sp_arm32.c +++ b/wolfcrypt/src/sp_arm32.c @@ -82768,17 +82768,21 @@ static int sp_256_mont_sqrt_8(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_256(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 8); + SP_DECL_VAR(sp_digit, x, 6 * 8); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int32 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 8, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 8, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 8; + t = x + 4 * 8; sp_256_from_mp(x, 8, xm); err = sp_256_mod_mul_norm_8(x, x, p256_mod); @@ -82798,9 +82802,31 @@ int sp_ecc_uncompress_256(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_256_mont_add_8(y, y, x, p256_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 8U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_256_mont_sqrt_8(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_256_mont_sqr_8(x, y, p256_mod, p256_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_256_norm_8(x); + n = sp_256_cmp_8(x, p256_mod); + sp_256_cond_sub_8(x, x, p256_mod, (sp_digit)~(n >> 31)); + sp_256_norm_8(x); + sp_256_norm_8(t); + n = sp_256_cmp_8(t, p256_mod); + sp_256_cond_sub_8(t, t, p256_mod, (sp_digit)~(n >> 31)); + sp_256_norm_8(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_256_cmp_equal_8(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 8, 0, 8U * sizeof(sp_digit)); sp_256_mont_reduce_8(y, p256_mod, p256_mp_mod); @@ -101941,17 +101967,21 @@ static int sp_384_mont_sqrt_12(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_384(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 12); + SP_DECL_VAR(sp_digit, x, 6 * 12); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int32 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 12, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 12, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 12; + t = x + 4 * 12; sp_384_from_mp(x, 12, xm); err = sp_384_mod_mul_norm_12(x, x, p384_mod); @@ -101971,9 +102001,31 @@ int sp_ecc_uncompress_384(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_384_mont_add_12(y, y, x, p384_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 12U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_384_mont_sqrt_12(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_384_mont_sqr_12(x, y, p384_mod, p384_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_384_norm_12(x); + n = sp_384_cmp_12(x, p384_mod); + sp_384_cond_sub_12(x, x, p384_mod, (sp_digit)~(n >> 31)); + sp_384_norm_12(x); + sp_384_norm_12(t); + n = sp_384_cmp_12(t, p384_mod); + sp_384_cond_sub_12(t, t, p384_mod, (sp_digit)~(n >> 31)); + sp_384_norm_12(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_384_cmp_equal_12(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 12, 0, 12U * sizeof(sp_digit)); sp_384_mont_reduce_12(y, p384_mod, p384_mp_mod); @@ -131747,17 +131799,21 @@ static int sp_521_mont_sqrt_17(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_521(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 17); + SP_DECL_VAR(sp_digit, x, 6 * 17); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int32 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 17, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 17, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 17; + t = x + 4 * 17; sp_521_from_mp(x, 17, xm); err = sp_521_mod_mul_norm_17(x, x, p521_mod); @@ -131777,9 +131833,31 @@ int sp_ecc_uncompress_521(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_521_mont_add_17(y, y, x, p521_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 17U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_521_mont_sqrt_17(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_521_mont_sqr_17(x, y, p521_mod, p521_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_521_norm_17(x); + n = sp_521_cmp_17(x, p521_mod); + sp_521_cond_sub_17(x, x, p521_mod, (sp_digit)~(n >> 31)); + sp_521_norm_17(x); + sp_521_norm_17(t); + n = sp_521_cmp_17(t, p521_mod); + sp_521_cond_sub_17(t, t, p521_mod, (sp_digit)~(n >> 31)); + sp_521_norm_17(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_521_cmp_equal_17(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 17, 0, 17U * sizeof(sp_digit)); sp_521_mont_reduce_17(y, p521_mod, p521_mp_mod); diff --git a/wolfcrypt/src/sp_arm64.c b/wolfcrypt/src/sp_arm64.c index d91647c5590..3eece20a5ef 100644 --- a/wolfcrypt/src/sp_arm64.c +++ b/wolfcrypt/src/sp_arm64.c @@ -58970,17 +58970,21 @@ static int sp_256_mont_sqrt_4(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_256(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 4); + SP_DECL_VAR(sp_digit, x, 6 * 4); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int64 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 4, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 4, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 4; + t = x + 4 * 4; sp_256_from_mp(x, 4, xm); err = sp_256_mod_mul_norm_4(x, x, p256_mod); @@ -59000,9 +59004,31 @@ int sp_ecc_uncompress_256(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_256_mont_add_4(y, y, x, p256_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 4U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_256_mont_sqrt_4(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_256_mont_sqr_4(x, y, p256_mod, p256_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_256_norm_4(x); + n = sp_256_cmp_4(x, p256_mod); + sp_256_cond_sub_4(x, x, p256_mod, (sp_digit)~(n >> 63)); + sp_256_norm_4(x); + sp_256_norm_4(t); + n = sp_256_cmp_4(t, p256_mod); + sp_256_cond_sub_4(t, t, p256_mod, (sp_digit)~(n >> 63)); + sp_256_norm_4(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_256_cmp_equal_4(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 4, 0, 4U * sizeof(sp_digit)); sp_256_mont_reduce_4(y, p256_mod, p256_mp_mod); @@ -85335,17 +85361,21 @@ static int sp_384_mont_sqrt_6(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_384(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 6); + SP_DECL_VAR(sp_digit, x, 6 * 6); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int64 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 6, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 6, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 6; + t = x + 4 * 6; sp_384_from_mp(x, 6, xm); err = sp_384_mod_mul_norm_6(x, x, p384_mod); @@ -85365,9 +85395,31 @@ int sp_ecc_uncompress_384(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_384_mont_add_6(y, y, x, p384_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 6U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_384_mont_sqrt_6(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_384_mont_sqr_6(x, y, p384_mod, p384_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_384_norm_6(x); + n = sp_384_cmp_6(x, p384_mod); + sp_384_cond_sub_6(x, x, p384_mod, (sp_digit)~(n >> 63)); + sp_384_norm_6(x); + sp_384_norm_6(t); + n = sp_384_cmp_6(t, p384_mod); + sp_384_cond_sub_6(t, t, p384_mod, (sp_digit)~(n >> 63)); + sp_384_norm_6(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_384_cmp_equal_6(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 6, 0, 6U * sizeof(sp_digit)); sp_384_mont_reduce_6(y, p384_mod, p384_mp_mod); @@ -130525,17 +130577,21 @@ static int sp_521_mont_sqrt_9(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_521(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 9); + SP_DECL_VAR(sp_digit, x, 6 * 9); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int64 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 9, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 9, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 9; + t = x + 4 * 9; sp_521_from_mp(x, 9, xm); err = sp_521_mod_mul_norm_9(x, x, p521_mod); @@ -130555,9 +130611,31 @@ int sp_ecc_uncompress_521(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_521_mont_add_9(y, y, x, p521_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 9U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_521_mont_sqrt_9(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_521_mont_sqr_9(x, y, p521_mod, p521_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_521_norm_9(x); + n = sp_521_cmp_9(x, p521_mod); + sp_521_cond_sub_9(x, x, p521_mod, (sp_digit)~(n >> 63)); + sp_521_norm_9(x); + sp_521_norm_9(t); + n = sp_521_cmp_9(t, p521_mod); + sp_521_cond_sub_9(t, t, p521_mod, (sp_digit)~(n >> 63)); + sp_521_norm_9(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_521_cmp_equal_9(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 9, 0, 9U * sizeof(sp_digit)); sp_521_mont_reduce_9(y, p521_mod, p521_mp_mod); diff --git a/wolfcrypt/src/sp_armthumb.c b/wolfcrypt/src/sp_armthumb.c index 8f03409b472..f8420c31caa 100644 --- a/wolfcrypt/src/sp_armthumb.c +++ b/wolfcrypt/src/sp_armthumb.c @@ -109279,17 +109279,21 @@ static int sp_256_mont_sqrt_8(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_256(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 8); + SP_DECL_VAR(sp_digit, x, 6 * 8); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int32 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 8, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 8, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 8; + t = x + 4 * 8; sp_256_from_mp(x, 8, xm); err = sp_256_mod_mul_norm_8(x, x, p256_mod); @@ -109309,9 +109313,31 @@ int sp_ecc_uncompress_256(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_256_mont_add_8(y, y, x, p256_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 8U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_256_mont_sqrt_8(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_256_mont_sqr_8(x, y, p256_mod, p256_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_256_norm_8(x); + n = sp_256_cmp_8(x, p256_mod); + sp_256_cond_sub_8(x, x, p256_mod, (sp_digit)~(n >> 31)); + sp_256_norm_8(x); + sp_256_norm_8(t); + n = sp_256_cmp_8(t, p256_mod); + sp_256_cond_sub_8(t, t, p256_mod, (sp_digit)~(n >> 31)); + sp_256_norm_8(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_256_cmp_equal_8(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 8, 0, 8U * sizeof(sp_digit)); sp_256_mont_reduce_8(y, p256_mod, p256_mp_mod); @@ -120955,17 +120981,21 @@ static int sp_384_mont_sqrt_12(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_384(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 12); + SP_DECL_VAR(sp_digit, x, 6 * 12); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int32 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 12, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 12, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 12; + t = x + 4 * 12; sp_384_from_mp(x, 12, xm); err = sp_384_mod_mul_norm_12(x, x, p384_mod); @@ -120985,9 +121015,31 @@ int sp_ecc_uncompress_384(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_384_mont_add_12(y, y, x, p384_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 12U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_384_mont_sqrt_12(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_384_mont_sqr_12(x, y, p384_mod, p384_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_384_norm_12(x); + n = sp_384_cmp_12(x, p384_mod); + sp_384_cond_sub_12(x, x, p384_mod, (sp_digit)~(n >> 31)); + sp_384_norm_12(x); + sp_384_norm_12(t); + n = sp_384_cmp_12(t, p384_mod); + sp_384_cond_sub_12(t, t, p384_mod, (sp_digit)~(n >> 31)); + sp_384_norm_12(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_384_cmp_equal_12(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 12, 0, 12U * sizeof(sp_digit)); sp_384_mont_reduce_12(y, p384_mod, p384_mp_mod); @@ -138384,17 +138436,21 @@ static int sp_521_mont_sqrt_17(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_521(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 17); + SP_DECL_VAR(sp_digit, x, 6 * 17); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int32 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 17, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 17, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 17; + t = x + 4 * 17; sp_521_from_mp(x, 17, xm); err = sp_521_mod_mul_norm_17(x, x, p521_mod); @@ -138414,9 +138470,31 @@ int sp_ecc_uncompress_521(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_521_mont_add_17(y, y, x, p521_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 17U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_521_mont_sqrt_17(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_521_mont_sqr_17(x, y, p521_mod, p521_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_521_norm_17(x); + n = sp_521_cmp_17(x, p521_mod); + sp_521_cond_sub_17(x, x, p521_mod, (sp_digit)~(n >> 31)); + sp_521_norm_17(x); + sp_521_norm_17(t); + n = sp_521_cmp_17(t, p521_mod); + sp_521_cond_sub_17(t, t, p521_mod, (sp_digit)~(n >> 31)); + sp_521_norm_17(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_521_cmp_equal_17(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 17, 0, 17U * sizeof(sp_digit)); sp_521_mont_reduce_17(y, p521_mod, p521_mp_mod); diff --git a/wolfcrypt/src/sp_c32.c b/wolfcrypt/src/sp_c32.c index 3edd0cd1dd8..a77950d41cf 100644 --- a/wolfcrypt/src/sp_c32.c +++ b/wolfcrypt/src/sp_c32.c @@ -30991,17 +30991,21 @@ static int sp_256_mont_sqrt_9(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_256(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 9); + SP_DECL_VAR(sp_digit, x, 6 * 9); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int32 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 9, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 9, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 9; + t = x + 4 * 9; sp_256_from_mp(x, 9, xm); err = sp_256_mod_mul_norm_9(x, x, p256_mod); @@ -31021,9 +31025,31 @@ int sp_ecc_uncompress_256(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_256_mont_add_9(y, y, x, p256_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 9U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_256_mont_sqrt_9(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_256_mont_sqr_9(x, y, p256_mod, p256_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_256_norm_9(x); + n = sp_256_cmp_9(x, p256_mod); + sp_256_cond_sub_9(x, x, p256_mod, (sp_digit)~(n >> 28)); + sp_256_norm_9(x); + sp_256_norm_9(t); + n = sp_256_cmp_9(t, p256_mod); + sp_256_cond_sub_9(t, t, p256_mod, (sp_digit)~(n >> 28)); + sp_256_norm_9(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_256_cmp_equal_9(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 9, 0, 9U * sizeof(sp_digit)); sp_256_mont_reduce_9(y, p256_mod, p256_mp_mod); @@ -39247,17 +39273,21 @@ static int sp_384_mont_sqrt_15(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_384(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 15); + SP_DECL_VAR(sp_digit, x, 6 * 15); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int32 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 15, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 15, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 15; + t = x + 4 * 15; sp_384_from_mp(x, 15, xm); err = sp_384_mod_mul_norm_15(x, x, p384_mod); @@ -39277,9 +39307,31 @@ int sp_ecc_uncompress_384(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_384_mont_add_15(y, y, x, p384_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 15U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_384_mont_sqrt_15(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_384_mont_sqr_15(x, y, p384_mod, p384_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_384_norm_15(x); + n = sp_384_cmp_15(x, p384_mod); + sp_384_cond_sub_15(x, x, p384_mod, (sp_digit)~(n >> 25)); + sp_384_norm_15(x); + sp_384_norm_15(t); + n = sp_384_cmp_15(t, p384_mod); + sp_384_cond_sub_15(t, t, p384_mod, (sp_digit)~(n >> 25)); + sp_384_norm_15(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_384_cmp_equal_15(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 15, 0, 15U * sizeof(sp_digit)); sp_384_mont_reduce_15(y, p384_mod, p384_mp_mod); @@ -47535,17 +47587,21 @@ static int sp_521_mont_sqrt_21(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_521(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 21); + SP_DECL_VAR(sp_digit, x, 6 * 21); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int32 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 21, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 21, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 21; + t = x + 4 * 21; sp_521_from_mp(x, 21, xm); err = sp_521_mod_mul_norm_21(x, x, p521_mod); @@ -47565,9 +47621,31 @@ int sp_ecc_uncompress_521(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_521_mont_add_21(y, y, x, p521_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 21U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_521_mont_sqrt_21(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_521_mont_sqr_21(x, y, p521_mod, p521_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_521_norm_21(x); + n = sp_521_cmp_21(x, p521_mod); + sp_521_cond_sub_21(x, x, p521_mod, (sp_digit)~(n >> 24)); + sp_521_norm_21(x); + sp_521_norm_21(t); + n = sp_521_cmp_21(t, p521_mod); + sp_521_cond_sub_21(t, t, p521_mod, (sp_digit)~(n >> 24)); + sp_521_norm_21(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_521_cmp_equal_21(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 21, 0, 21U * sizeof(sp_digit)); sp_521_mont_reduce_21(y, p521_mod, p521_mp_mod); diff --git a/wolfcrypt/src/sp_c64.c b/wolfcrypt/src/sp_c64.c index 93da67e2df6..6ab697ef2a6 100644 --- a/wolfcrypt/src/sp_c64.c +++ b/wolfcrypt/src/sp_c64.c @@ -32248,17 +32248,21 @@ static int sp_256_mont_sqrt_5(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_256(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 5); + SP_DECL_VAR(sp_digit, x, 6 * 5); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int64 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 5, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 5, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 5; + t = x + 4 * 5; sp_256_from_mp(x, 5, xm); err = sp_256_mod_mul_norm_5(x, x, p256_mod); @@ -32278,9 +32282,31 @@ int sp_ecc_uncompress_256(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_256_mont_add_5(y, y, x, p256_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 5U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_256_mont_sqrt_5(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_256_mont_sqr_5(x, y, p256_mod, p256_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_256_norm_5(x); + n = sp_256_cmp_5(x, p256_mod); + sp_256_cond_sub_5(x, x, p256_mod, (sp_digit)~(n >> 51)); + sp_256_norm_5(x); + sp_256_norm_5(t); + n = sp_256_cmp_5(t, p256_mod); + sp_256_cond_sub_5(t, t, p256_mod, (sp_digit)~(n >> 51)); + sp_256_norm_5(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_256_cmp_equal_5(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 5, 0, 5U * sizeof(sp_digit)); sp_256_mont_reduce_5(y, p256_mod, p256_mp_mod); @@ -39891,17 +39917,21 @@ static int sp_384_mont_sqrt_7(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_384(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 7); + SP_DECL_VAR(sp_digit, x, 6 * 7); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int64 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 7, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 7, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 7; + t = x + 4 * 7; sp_384_from_mp(x, 7, xm); err = sp_384_mod_mul_norm_7(x, x, p384_mod); @@ -39921,9 +39951,31 @@ int sp_ecc_uncompress_384(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_384_mont_add_7(y, y, x, p384_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 7U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_384_mont_sqrt_7(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_384_mont_sqr_7(x, y, p384_mod, p384_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_384_norm_7(x); + n = sp_384_cmp_7(x, p384_mod); + sp_384_cond_sub_7(x, x, p384_mod, (sp_digit)~(n >> 54)); + sp_384_norm_7(x); + sp_384_norm_7(t); + n = sp_384_cmp_7(t, p384_mod); + sp_384_cond_sub_7(t, t, p384_mod, (sp_digit)~(n >> 54)); + sp_384_norm_7(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_384_cmp_equal_7(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 7, 0, 7U * sizeof(sp_digit)); sp_384_mont_reduce_7(y, p384_mod, p384_mp_mod); @@ -47489,17 +47541,21 @@ static int sp_521_mont_sqrt_9(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_521(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 9); + SP_DECL_VAR(sp_digit, x, 6 * 9); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int64 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 9, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 9, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 9; + t = x + 4 * 9; sp_521_from_mp(x, 9, xm); err = sp_521_mod_mul_norm_9(x, x, p521_mod); @@ -47519,9 +47575,31 @@ int sp_ecc_uncompress_521(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_521_mont_add_9(y, y, x, p521_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 9U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_521_mont_sqrt_9(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_521_mont_sqr_9(x, y, p521_mod, p521_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_521_norm_9(x); + n = sp_521_cmp_9(x, p521_mod); + sp_521_cond_sub_9(x, x, p521_mod, (sp_digit)~(n >> 57)); + sp_521_norm_9(x); + sp_521_norm_9(t); + n = sp_521_cmp_9(t, p521_mod); + sp_521_cond_sub_9(t, t, p521_mod, (sp_digit)~(n >> 57)); + sp_521_norm_9(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_521_cmp_equal_9(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 9, 0, 9U * sizeof(sp_digit)); sp_521_mont_reduce_9(y, p521_mod, p521_mp_mod); diff --git a/wolfcrypt/src/sp_cortexm.c b/wolfcrypt/src/sp_cortexm.c index 2c6b8a26b7c..47729f2baa3 100644 --- a/wolfcrypt/src/sp_cortexm.c +++ b/wolfcrypt/src/sp_cortexm.c @@ -47259,17 +47259,21 @@ static int sp_256_mont_sqrt_8(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_256(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 8); + SP_DECL_VAR(sp_digit, x, 6 * 8); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int32 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 8, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 8, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 8; + t = x + 4 * 8; sp_256_from_mp(x, 8, xm); err = sp_256_mod_mul_norm_8(x, x, p256_mod); @@ -47289,9 +47293,31 @@ int sp_ecc_uncompress_256(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_256_mont_add_8(y, y, x, p256_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 8U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_256_mont_sqrt_8(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_256_mont_sqr_8(x, y, p256_mod, p256_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_256_norm_8(x); + n = sp_256_cmp_8(x, p256_mod); + sp_256_cond_sub_8(x, x, p256_mod, (sp_digit)~(n >> 31)); + sp_256_norm_8(x); + sp_256_norm_8(t); + n = sp_256_cmp_8(t, p256_mod); + sp_256_cond_sub_8(t, t, p256_mod, (sp_digit)~(n >> 31)); + sp_256_norm_8(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_256_cmp_equal_8(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 8, 0, 8U * sizeof(sp_digit)); sp_256_mont_reduce_8(y, p256_mod, p256_mp_mod); @@ -58787,17 +58813,21 @@ static int sp_384_mont_sqrt_12(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_384(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 12); + SP_DECL_VAR(sp_digit, x, 6 * 12); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int32 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 12, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 12, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 12; + t = x + 4 * 12; sp_384_from_mp(x, 12, xm); err = sp_384_mod_mul_norm_12(x, x, p384_mod); @@ -58817,9 +58847,31 @@ int sp_ecc_uncompress_384(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_384_mont_add_12(y, y, x, p384_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 12U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_384_mont_sqrt_12(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_384_mont_sqr_12(x, y, p384_mod, p384_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_384_norm_12(x); + n = sp_384_cmp_12(x, p384_mod); + sp_384_cond_sub_12(x, x, p384_mod, (sp_digit)~(n >> 31)); + sp_384_norm_12(x); + sp_384_norm_12(t); + n = sp_384_cmp_12(t, p384_mod); + sp_384_cond_sub_12(t, t, p384_mod, (sp_digit)~(n >> 31)); + sp_384_norm_12(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_384_cmp_equal_12(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 12, 0, 12U * sizeof(sp_digit)); sp_384_mont_reduce_12(y, p384_mod, p384_mp_mod); @@ -73642,17 +73694,21 @@ static int sp_521_mont_sqrt_17(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_521(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 17); + SP_DECL_VAR(sp_digit, x, 6 * 17); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int32 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 17, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 17, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 17; + t = x + 4 * 17; sp_521_from_mp(x, 17, xm); err = sp_521_mod_mul_norm_17(x, x, p521_mod); @@ -73672,9 +73728,31 @@ int sp_ecc_uncompress_521(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_521_mont_add_17(y, y, x, p521_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 17U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_521_mont_sqrt_17(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_521_mont_sqr_17(x, y, p521_mod, p521_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_521_norm_17(x); + n = sp_521_cmp_17(x, p521_mod); + sp_521_cond_sub_17(x, x, p521_mod, (sp_digit)~(n >> 31)); + sp_521_norm_17(x); + sp_521_norm_17(t); + n = sp_521_cmp_17(t, p521_mod); + sp_521_cond_sub_17(t, t, p521_mod, (sp_digit)~(n >> 31)); + sp_521_norm_17(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_521_cmp_equal_17(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 17, 0, 17U * sizeof(sp_digit)); sp_521_mont_reduce_17(y, p521_mod, p521_mp_mod); diff --git a/wolfcrypt/src/sp_dsp32.c b/wolfcrypt/src/sp_dsp32.c index 2a902875e75..15ad091b7f9 100644 --- a/wolfcrypt/src/sp_dsp32.c +++ b/wolfcrypt/src/sp_dsp32.c @@ -4833,13 +4833,16 @@ int sp_ecc_uncompress_256(mp_int* xm, int odd, mp_int* ym) #else sp_digit xd[2 * 10]; sp_digit yd[2 * 10]; + sp_digit td[2 * 10]; #endif sp_digit* x = NULL; sp_digit* y = NULL; + sp_digit* t = NULL; + int32_t n; int err = MP_OKAY; #if defined(WOLFSSL_SP_SMALL) || defined(WOLFSSL_SMALL_STACK) - d = (sp_digit*)XMALLOC(sizeof(sp_digit) * 4 * 10, NULL, DYNAMIC_TYPE_ECC); + d = (sp_digit*)XMALLOC(sizeof(sp_digit) * 6 * 10, NULL, DYNAMIC_TYPE_ECC); if (d == NULL) { err = MEMORY_E; } @@ -4849,9 +4852,11 @@ int sp_ecc_uncompress_256(mp_int* xm, int odd, mp_int* ym) #if defined(WOLFSSL_SP_SMALL) || defined(WOLFSSL_SMALL_STACK) x = d + 0 * 10; y = d + 2 * 10; + t = d + 4 * 10; #else x = xd; y = yd; + t = td; #endif sp_256_from_mp(x, 10, xm); @@ -4872,9 +4877,33 @@ int sp_ecc_uncompress_256(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_256_mont_add_10(y, y, x, p256_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 10U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_256_mont_sqrt_10(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_256_mont_sqr_10(x, y, p256_mod, p256_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_256_norm_10(x); + n = sp_256_cmp_10(x, p256_mod); + sp_256_cond_sub_10(x, x, p256_mod, 0 - ((n >= 0) ? + (sp_digit)1 : (sp_digit)0)); + sp_256_norm_10(x); + sp_256_norm_10(t); + n = sp_256_cmp_10(t, p256_mod); + sp_256_cond_sub_10(t, t, p256_mod, 0 - ((n >= 0) ? + (sp_digit)1 : (sp_digit)0)); + sp_256_norm_10(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_256_cmp_equal_10(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 10, 0, 10U * sizeof(sp_digit)); sp_256_mont_reduce_10(y, p256_mod, p256_mp_mod); diff --git a/wolfcrypt/src/sp_riscv64.c b/wolfcrypt/src/sp_riscv64.c index a4b1f4f85e1..def6962997b 100644 --- a/wolfcrypt/src/sp_riscv64.c +++ b/wolfcrypt/src/sp_riscv64.c @@ -45457,17 +45457,21 @@ static int sp_256_mont_sqrt_4(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_256(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 4); + SP_DECL_VAR(sp_digit, x, 6 * 4); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int64 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 4, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 4, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 4; + t = x + 4 * 4; sp_256_from_mp(x, 4, xm); err = sp_256_mod_mul_norm_4(x, x, p256_mod); @@ -45487,9 +45491,31 @@ int sp_ecc_uncompress_256(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_256_mont_add_4(y, y, x, p256_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 4U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_256_mont_sqrt_4(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_256_mont_sqr_4(x, y, p256_mod, p256_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_256_norm_4(x); + n = sp_256_cmp_4(x, p256_mod); + sp_256_cond_sub_4(x, x, p256_mod, (sp_digit)~(n >> 63)); + sp_256_norm_4(x); + sp_256_norm_4(t); + n = sp_256_cmp_4(t, p256_mod); + sp_256_cond_sub_4(t, t, p256_mod, (sp_digit)~(n >> 63)); + sp_256_norm_4(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_256_cmp_equal_4(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 4, 0, 4U * sizeof(sp_digit)); sp_256_mont_reduce_4(y, p256_mod, p256_mp_mod); @@ -56192,17 +56218,21 @@ static int sp_384_mont_sqrt_6(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_384(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 6); + SP_DECL_VAR(sp_digit, x, 6 * 6); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int64 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 6, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 6, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 6; + t = x + 4 * 6; sp_384_from_mp(x, 6, xm); err = sp_384_mod_mul_norm_6(x, x, p384_mod); @@ -56222,9 +56252,31 @@ int sp_ecc_uncompress_384(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_384_mont_add_6(y, y, x, p384_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 6U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_384_mont_sqrt_6(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_384_mont_sqr_6(x, y, p384_mod, p384_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_384_norm_6(x); + n = sp_384_cmp_6(x, p384_mod); + sp_384_cond_sub_6(x, x, p384_mod, (sp_digit)~(n >> 63)); + sp_384_norm_6(x); + sp_384_norm_6(t); + n = sp_384_cmp_6(t, p384_mod); + sp_384_cond_sub_6(t, t, p384_mod, (sp_digit)~(n >> 63)); + sp_384_norm_6(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_384_cmp_equal_6(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 6, 0, 6U * sizeof(sp_digit)); sp_384_mont_reduce_6(y, p384_mod, p384_mp_mod); @@ -67134,17 +67186,21 @@ static int sp_521_mont_sqrt_9(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_521(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 9); + SP_DECL_VAR(sp_digit, x, 6 * 9); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int64 n; int err = MP_OKAY; - SP_ALLOC_VAR(sp_digit, x, 4 * 9, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 9, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 9; + t = x + 4 * 9; sp_521_from_mp(x, 9, xm); err = sp_521_mod_mul_norm_9(x, x, p521_mod); @@ -67164,9 +67220,31 @@ int sp_ecc_uncompress_521(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_521_mont_add_9(y, y, x, p521_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 9U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_521_mont_sqrt_9(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_521_mont_sqr_9(x, y, p521_mod, p521_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_521_norm_9(x); + n = sp_521_cmp_9(x, p521_mod); + sp_521_cond_sub_9(x, x, p521_mod, (sp_digit)~(n >> 63)); + sp_521_norm_9(x); + sp_521_norm_9(t); + n = sp_521_cmp_9(t, p521_mod); + sp_521_cond_sub_9(t, t, p521_mod, (sp_digit)~(n >> 63)); + sp_521_norm_9(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_521_cmp_equal_9(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 9, 0, 9U * sizeof(sp_digit)); sp_521_mont_reduce_9(y, p521_mod, p521_mp_mod); diff --git a/wolfcrypt/src/sp_x86_64.c b/wolfcrypt/src/sp_x86_64.c index 55aee80c519..0f6bc060d9c 100644 --- a/wolfcrypt/src/sp_x86_64.c +++ b/wolfcrypt/src/sp_x86_64.c @@ -26841,20 +26841,24 @@ static int sp_256_mont_sqrt_4(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_256(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 4); + SP_DECL_VAR(sp_digit, x, 6 * 4); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int64 n; int err = MP_OKAY; #ifdef HAVE_INTEL_AVX2 word32 cpuid_flags = cpuid_get_flags(); #endif - SP_ALLOC_VAR(sp_digit, x, 4 * 4, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 4, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 4; + t = x + 4 * 4; sp_256_from_mp(x, 4, xm); err = sp_256_mod_mul_norm_4(x, x, p256_mod); @@ -26888,9 +26892,31 @@ int sp_ecc_uncompress_256(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_256_mont_add_4(y, y, x, p256_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 4U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_256_mont_sqrt_4(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_256_mont_sqr_4(x, y, p256_mod, p256_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_256_norm_4(x); + n = sp_256_cmp_4(x, p256_mod); + sp_256_cond_sub_4(x, x, p256_mod, (sp_digit)~(n >> 63)); + sp_256_norm_4(x); + sp_256_norm_4(t); + n = sp_256_cmp_4(t, p256_mod); + sp_256_cond_sub_4(t, t, p256_mod, (sp_digit)~(n >> 63)); + sp_256_norm_4(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_256_cmp_equal_4(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 4, 0, 4U * sizeof(sp_digit)); sp_256_mont_reduce_4(y, p256_mod, p256_mp_mod); @@ -51827,20 +51853,24 @@ static int sp_384_mont_sqrt_6(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_384(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 6); + SP_DECL_VAR(sp_digit, x, 6 * 6); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int64 n; int err = MP_OKAY; #ifdef HAVE_INTEL_AVX2 word32 cpuid_flags = cpuid_get_flags(); #endif - SP_ALLOC_VAR(sp_digit, x, 4 * 6, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 6, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 6; + t = x + 4 * 6; sp_384_from_mp(x, 6, xm); err = sp_384_mod_mul_norm_6(x, x, p384_mod); @@ -51874,9 +51904,31 @@ int sp_ecc_uncompress_384(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_384_mont_add_6(y, y, x, p384_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 6U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_384_mont_sqrt_6(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_384_mont_sqr_6(x, y, p384_mod, p384_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_384_norm_6(x); + n = sp_384_cmp_6(x, p384_mod); + sp_384_cond_sub_6(x, x, p384_mod, (sp_digit)~(n >> 63)); + sp_384_norm_6(x); + sp_384_norm_6(t); + n = sp_384_cmp_6(t, p384_mod); + sp_384_cond_sub_6(t, t, p384_mod, (sp_digit)~(n >> 63)); + sp_384_norm_6(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_384_cmp_equal_6(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 6, 0, 6U * sizeof(sp_digit)); sp_384_mont_reduce_6(y, p384_mod, p384_mp_mod); @@ -92871,20 +92923,24 @@ static int sp_521_mont_sqrt_9(sp_digit* y) * @param [out] ym Calculated Y ordinate. * * @return MP_OKAY otherwise. + * @return MP_VAL when no point on the curve has the X ordinate. * @return MEMORY_E when dynamic memory allocation fails. */ int sp_ecc_uncompress_521(mp_int* xm, int odd, mp_int* ym) { - SP_DECL_VAR(sp_digit, x, 4 * 9); + SP_DECL_VAR(sp_digit, x, 6 * 9); sp_digit* y = NULL; + sp_digit* t = NULL; + sp_int64 n; int err = MP_OKAY; #ifdef HAVE_INTEL_AVX2 word32 cpuid_flags = cpuid_get_flags(); #endif - SP_ALLOC_VAR(sp_digit, x, 4 * 9, NULL, DYNAMIC_TYPE_ECC); + SP_ALLOC_VAR(sp_digit, x, 6 * 9, NULL, DYNAMIC_TYPE_ECC); if (err == MP_OKAY) { y = x + 2 * 9; + t = x + 4 * 9; sp_521_from_mp(x, 9, xm); err = sp_521_mod_mul_norm_9(x, x, p521_mod); @@ -92918,9 +92974,31 @@ int sp_ecc_uncompress_521(mp_int* xm, int odd, mp_int* ym) } if (err == MP_OKAY) { sp_521_mont_add_9(y, y, x, p521_mod); + /* t = x^3 - 3x + b */ + XMEMCPY(t, y, 9U * sizeof(sp_digit)); /* y = sqrt(x^3 - 3x + b) */ err = sp_521_mont_sqrt_9(y); } + if (err == MP_OKAY) { + /* x = y^2 */ + sp_521_mont_sqr_9(x, y, p521_mod, p521_mp_mod); + /* Reduce both sides to less than the modulus before comparing: a + * Montgomery result may still be in [p, 2^bits) or carry an + * unpropagated limb. */ + sp_521_norm_9(x); + n = sp_521_cmp_9(x, p521_mod); + sp_521_cond_sub_9(x, x, p521_mod, (sp_digit)~(n >> 63)); + sp_521_norm_9(x); + sp_521_norm_9(t); + n = sp_521_cmp_9(t, p521_mod); + sp_521_cond_sub_9(t, t, p521_mod, (sp_digit)~(n >> 63)); + sp_521_norm_9(t); + /* No square root exists when y^2 != x^3 - 3x + b: no point has this + * x ordinate. */ + if (sp_521_cmp_equal_9(x, t) == 0) { + err = MP_VAL; + } + } if (err == MP_OKAY) { XMEMSET(y + 9, 0, 9U * sizeof(sp_digit)); sp_521_mont_reduce_9(y, p521_mod, p521_mp_mod); diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index f36e7096961..961c6f6baa6 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -54934,6 +54934,12 @@ static wc_test_ret_t ecc_test_curve_size(WC_RNG* rng, int keySize, int testVerif #endif /* HAVE_ECC_DHE */ #ifdef HAVE_COMP_KEY + #ifdef SQRTMOD_USE_MOD_EXP + /* The single exponentiation square root does not support a prime that + * is 1 mod 8, so a compressed P-224 point cannot be imported. */ + if (userA->dp->id != ECC_SECP224R1) + #endif + { /* try compressed export / import too */ x = ECC_KEY_EXPORT_BUF_SIZE; #if FIPS_VERSION3_GE(6,0,0) && FIPS_VERSION3_LT(7,0,0) @@ -54979,6 +54985,7 @@ static wc_test_ret_t ecc_test_curve_size(WC_RNG* rng, int keySize, int testVerif ERROR_OUT(WC_TEST_RET_ENC_NC, done); TEST_SLEEP(); #endif /* HAVE_ECC_DHE */ + } #endif /* HAVE_COMP_KEY */ #endif /* !WOLFSSL_ATECC508A && !WOLFSSL_ATECC608A */