Merge pull request #10529 from SparkiDev/sp_fixes_8

sp_int: fixes and added testing
This commit is contained in:
JacobBarthelmeh
2026-05-27 10:59:24 -06:00
committed by GitHub
2 changed files with 632 additions and 17 deletions
+13 -7
View File
@@ -6143,6 +6143,13 @@ int sp_set_bit(sp_int* a, int i)
/* Get index of word to set. */
sp_size_t w = (sp_size_t)(i >> SP_WORD_SHIFT);
#if SP_INT_DIGITS < (65536 / SP_WORD_SIZEOF)
/* Check bit index isn't bigger than maximum allowed. */
if (i > SP_INT_DIGITS * SP_WORD_SIZE) {
err = MP_VAL;
}
else
#endif
/* Check for valid number and space for bit. */
if ((a == NULL) || (i < 0) || (w >= a->size)) {
err = MP_VAL;
@@ -7408,9 +7415,7 @@ static void _sp_div_2(const sp_int* a, sp_int* r)
/* Last word only needs to be shifted down. */
r->dp[i] = a->dp[i] >> 1;
/* Set used to be all words seen. */
r->used = (sp_size_t)(i + 1);
/* Remove leading zeros. */
sp_clamp(r);
r->used = (sp_size_t)(i + 1 - (int)((r->dp[i] - 1) >> (SP_WORD_SIZE - 1)));
#ifdef WOLFSSL_SP_INT_NEGATIVE
/* Same sign in result. */
r->sign = a->sign;
@@ -7892,7 +7897,7 @@ int sp_sub(const sp_int* a, const sp_int* b, sp_int* r)
else {
/* Reverse subtract absolute values and use opposite sign of a */
_sp_sub_off(b, a, r, 0);
r->sign = 1 - a->sign;
r->sign = (sp_sign_t)(1 - a->sign);
}
#endif
}
@@ -8049,7 +8054,8 @@ static int _sp_submod(const sp_int* a, const sp_int* b, const sp_int* m,
FREE_SP_INT(t0, NULL);
FREE_SP_INT(t1, NULL);
#else /* WOLFSSL_SP_INT_NEGATIVE */
sp_size_t used = ((a->used >= b->used) ? a->used + 1 : b->used + 1);
sp_size_t used = (sp_size_t)((a->used >= b->used) ? a->used + 1 :
b->used + 1);
DECL_SP_INT(t, used);
ALLOC_SP_INT_SIZE(t, used, err, NULL);
@@ -9199,7 +9205,7 @@ static int _sp_mod(const sp_int* a, const sp_int* m, sp_int* r)
/* In case remainder is modulus - allocate temporary. */
ALLOC_SP_INT(t, a->used + 1, err, NULL);
if (err == MP_OKAY) {
_sp_init_size(t, a->used + 1);
_sp_init_size(t, (sp_size_t)(a->used + 1));
/* Use divide to calculate remainder and don't get quotient. */
err = sp_div(a, m, NULL, t);
}
@@ -15056,7 +15062,7 @@ static int _sp_sqr(const sp_int* a, sp_int* r)
#elif defined(WOLFSSL_SP_DYN_STACK)
sp_int_digit t[((a->used + 1) / 2) * 2 + 1];
#else
sp_int_digit t[(SP_INT_DIGITS + 1) / 2];
sp_int_digit t[(SP_INT_DIGITS + 1) / 2 + 1];
#endif
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_SP_NO_MALLOC)
+619 -10
View File
@@ -67422,6 +67422,24 @@ static wc_test_ret_t mp_test_radix_10(mp_int* a, mp_int* r, WC_RNG* rng)
if (!mp_iszero(r))
return WC_TEST_RET_ENC_NC;
#ifdef WOLFSSL_SP_INT_NEGATIVE
/* Negative values are written with a leading '-' and read back. */
ret = mp_set(a, 12345);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
mp_setneg(a);
ret = mp_toradix(a, str, MP_RADIX_DEC);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
if (str[0] != '-')
return WC_TEST_RET_ENC_NC;
ret = mp_read_radix(r, str, MP_RADIX_DEC);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
if (mp_cmp(r, a) != MP_EQ)
return WC_TEST_RET_ENC_NC;
#endif
return 0;
}
#endif
@@ -67506,6 +67524,24 @@ static wc_test_ret_t mp_test_radix_16(mp_int* a, mp_int* r, WC_RNG* rng)
if (!mp_iszero(r))
return WC_TEST_RET_ENC_NC;
#ifdef WOLFSSL_SP_INT_NEGATIVE
/* Negative values are written with a leading '-' and read back. */
ret = mp_set(a, 0xABCD);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
mp_setneg(a);
ret = mp_toradix(a, str, MP_RADIX_HEX);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
if (str[0] != '-')
return WC_TEST_RET_ENC_NC;
ret = mp_read_radix(r, str, MP_RADIX_HEX);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
if (mp_cmp(r, a) != MP_EQ)
return WC_TEST_RET_ENC_NC;
#endif
#ifdef WOLFSSL_SP_MATH
ret = mp_toradix(a, str, 8);
if (ret != WC_NO_ERR_TRACE(MP_VAL))
@@ -67563,11 +67599,13 @@ static wc_test_ret_t mp_test_shift(mp_int* a, mp_int* r1, WC_RNG* rng)
#if !(defined(WOLFSSL_SP_MATH_ALL) || defined(WOLFSSL_SP_MATH)) || \
(defined(WOLFSSL_SP_ADD_D) && defined(WOLFSSL_SP_SUB_D))
static wc_test_ret_t mp_test_add_sub_d(mp_int* a, mp_int* r1)
static wc_test_ret_t mp_test_add_sub_d(mp_int* a, mp_int* b, mp_int* r1)
{
int i, j;
wc_test_ret_t ret;
(void)b;
for (i = 0; i <= DIGIT_BIT * 2; i++) {
mp_zero(a);
mp_set_bit(a, i);
@@ -67600,6 +67638,62 @@ static wc_test_ret_t mp_test_add_sub_d(mp_int* a, mp_int* r1)
if (r1->used != 0)
return WC_TEST_RET_ENC_NC;
#ifdef WOLFSSL_SP_INT_NEGATIVE
/* Adding/subtracting a digit to/from a negative value, and producing a
* negative result, exercise the signed digit paths. */
/* -100 + 5 = -95 */
ret = mp_set(a, 100);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
mp_setneg(a);
ret = mp_add_d(a, 5, r1);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
ret = mp_set(b, 95);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
mp_setneg(b);
if (mp_cmp(r1, b) != MP_EQ)
return WC_TEST_RET_ENC_NC;
/* -3 + 10 = 7 */
ret = mp_set(a, 3);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
mp_setneg(a);
ret = mp_add_d(a, 10, r1);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
if (mp_cmp_d(r1, 7) != MP_EQ)
return WC_TEST_RET_ENC_NC;
/* -5 - 3 = -8 */
ret = mp_set(a, 5);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
mp_setneg(a);
ret = mp_sub_d(a, 3, r1);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
ret = mp_set(b, 8);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
mp_setneg(b);
if (mp_cmp(r1, b) != MP_EQ)
return WC_TEST_RET_ENC_NC;
/* 3 - 10 = -7 */
ret = mp_set(a, 3);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
ret = mp_sub_d(a, 10, r1);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
ret = mp_set(b, 7);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
mp_setneg(b);
if (mp_cmp(r1, b) != MP_EQ)
return WC_TEST_RET_ENC_NC;
#endif /* WOLFSSL_SP_INT_NEGATIVE */
return 0;
}
#endif
@@ -68762,7 +68856,7 @@ static wc_test_ret_t mp_test_set_is_bit(mp_int* a)
}
#endif
#ifdef WOLFSSL_SP_MATH
#if defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL)
mp_zero(a);
for (j = 1; j <= 3; j++) {
i = SP_INT_MAX_BITS - j;
@@ -69264,19 +69358,28 @@ static wc_test_ret_t mp_test_prime(mp_int* a, WC_RNG* rng)
}
#endif
#if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && !defined(WC_RSA_BLINDING)
/* mp_gcd has less restrictive protections than mp_lcm.
* Test mp_gcd with and without mp_lcm. */
#if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)
#if !defined(WC_RSA_BLINDING) || defined(HAVE_FIPS) || defined(HAVE_SELFTEST)
#define MP_TEST_HAVE_LCM
#endif
static wc_test_ret_t mp_test_lcm_gcd(mp_int* a, mp_int* b, mp_int* r, mp_int* exp,
WC_RNG* rng)
{
wc_test_ret_t ret;
#ifdef MP_TEST_HAVE_LCM
int i;
WOLFSSL_SMALL_STACK_STATIC const int kat[][3] = {
{ 1, 1, 1 }, { 2, 1, 2 }, { 1, 2, 2 }, { 2, 4, 4 }, { 4, 2, 4 },
{ 12, 56, 168 }, { 56, 12, 168 }
};
#endif
(void)exp;
(void)rng;
#ifdef MP_TEST_HAVE_LCM
mp_set(a, 0);
mp_set(b, 1);
ret = mp_lcm(a, a, r);
@@ -69301,7 +69404,6 @@ static wc_test_ret_t mp_test_lcm_gcd(mp_int* a, mp_int* b, mp_int* r, mp_int* ex
return WC_TEST_RET_ENC_NC;
}
(void)rng;
#if defined(WOLFSSL_KEY_GEN) && (!defined(NO_DH) || !defined(NO_DSA)) && \
!defined(WC_NO_RNG)
ret = mp_rand_prime(a, 20, rng, NULL);
@@ -69326,7 +69428,9 @@ static wc_test_ret_t mp_test_lcm_gcd(mp_int* a, mp_int* b, mp_int* r, mp_int* ex
if (ret != MP_EQ)
return WC_TEST_RET_ENC_NC;
#endif
#endif /* MP_TEST_HAVE_LCM */
/* GCD with zero - returns the non-zero operand, zero/zero is invalid. */
mp_set(a, 11);
mp_zero(b);
ret = mp_gcd(a, b, r);
@@ -69345,6 +69449,57 @@ static wc_test_ret_t mp_test_lcm_gcd(mp_int* a, mp_int* b, mp_int* r, mp_int* ex
if (ret != WC_NO_ERR_TRACE(MP_VAL))
return WC_TEST_RET_ENC_EC(ret);
/* Multi-digit GCD exercising the Euclidean reduction loops.
* Uses the identity gcd(2^m - 1, 2^n - 1) = 2^gcd(m,n) - 1.
* gcd(2^192-1, 2^128-1) = 2^64-1: both operands multi-word so the
* smaller is reduced with the multi-word sp_mod() path. */
ret = mp_set(a, 1);
if (ret == MP_OKAY)
ret = mp_mul_2d(a, 192, a);
if (ret == MP_OKAY)
ret = mp_sub_d(a, 1, a);
if (ret == MP_OKAY)
ret = mp_set(b, 1);
if (ret == MP_OKAY)
ret = mp_mul_2d(b, 128, b);
if (ret == MP_OKAY)
ret = mp_sub_d(b, 1, b);
if (ret == MP_OKAY)
ret = mp_set(exp, 1);
if (ret == MP_OKAY)
ret = mp_mul_2d(exp, 64, exp);
if (ret == MP_OKAY)
ret = mp_sub_d(exp, 1, exp);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
/* a > b: exercises the operand swap. */
ret = mp_gcd(a, b, r);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
if (mp_cmp(r, exp) != MP_EQ)
return WC_TEST_RET_ENC_NC;
/* b < a: no swap. */
ret = mp_gcd(b, a, r);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
if (mp_cmp(r, exp) != MP_EQ)
return WC_TEST_RET_ENC_NC;
/* gcd(2^192-1, 2^64-1) = 2^64-1: smaller operand is a single word so
* the sp_mod_d() reduction path is exercised. */
ret = mp_set(b, 1);
if (ret == MP_OKAY)
ret = mp_mul_2d(b, 64, b);
if (ret == MP_OKAY)
ret = mp_sub_d(b, 1, b);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
ret = mp_gcd(a, b, r);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
if (mp_cmp(r, exp) != MP_EQ)
return WC_TEST_RET_ENC_NC;
return 0;
}
#endif
@@ -69479,14 +69634,47 @@ static wc_test_ret_t mp_test_mod_d(mp_int* a, WC_RNG* rng)
if (r != rem)
return WC_TEST_RET_ENC_NC;
}
/* Power-of-2 divisor uses the bitmask fast path. */
ret = mp_set(a, 0x1234);
if (ret == MP_OKAY)
ret = mp_mod_d(a, 8, &r);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
if (r != (0x1234 & 7))
return WC_TEST_RET_ENC_NC;
/* Divisor of 10 has a dedicated multi-word fast path. */
ret = randNum(a, MP_MAX_TEST_BYTE_LEN, rng, NULL);
if (ret == MP_OKAY)
ret = mp_mod_d(a, 10, &r);
if (ret == MP_OKAY)
ret = mp_div_d(a, 10, a, &rem);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
if (r != rem)
return WC_TEST_RET_ENC_NC;
#ifdef WOLFSSL_SP_INT_NEGATIVE
/* Test a negative value. */
ret = mp_set(a, 17);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
mp_setneg(a);
ret = mp_mod_d(a, 5, &r);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
if (r != 3)
return WC_TEST_RET_ENC_NC;
#endif
#endif
return 0;
}
#endif
static wc_test_ret_t mp_test_mul_sqr(mp_int* a, mp_int* b, mp_int* r1, mp_int* r2,
WC_RNG* rng)
static wc_test_ret_t mp_test_mul_sqr(mp_int* a, mp_int* b, mp_int* r1,
mp_int* r2, WC_RNG* rng)
{
wc_test_ret_t ret;
int i;
@@ -69567,11 +69755,270 @@ static wc_test_ret_t mp_test_mul_sqr(mp_int* a, mp_int* b, mp_int* r1, mp_int* r
return WC_TEST_RET_ENC_EC(ret);
#endif /* HAVE_ECC && (ECC_SHAMIR || FP_ECC) */
#endif /* WOLFSSL_SP_MATH_ALL || WOLFSSL_HAVE_SP_DH || (HAVE_ECC && FP_ECC) */
/* Check that the maximum value squared works. */
ret = mp_2expt(a, SP_INT_DIGITS / 2 * SP_WORD_SIZE);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
ret = mp_set(b, 1);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
ret = mp_sub(a, b, a);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
ret = mp_mul(a, a, r1);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
ret = mp_sqr(a, r2);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
if (mp_cmp(r1, r2) != MP_EQ)
return WC_TEST_RET_ENC_NC;
#endif /* WOLFSSL_SP_MATH_ALL */
return 0;
}
#if defined(WOLFSSL_SP_MATH_ALL) && defined(HAVE_ECC)
/* Functional tests for the constant-time modular arithmetic used by ECC:
* mp_addmod_ct, mp_submod_ct and mp_div_2_mod_ct. These are not reached by
* the parameter-validation tests so their computation paths are exercised
* here against their variable-time equivalents. */
static wc_test_ret_t mp_test_addsubmod_ct(mp_int* a, mp_int* b, mp_int* m,
mp_int* r, mp_int* t, WC_RNG* rng)
{
wc_test_ret_t res = 0;
int ret;
int i;
for (i = 0; (i < 16) && (res == 0); i++) {
/* Odd, multi-word modulus (2 must be invertible for div_2_mod_ct). */
ret = randNum(m, 24, rng, NULL);
if (ret == MP_OKAY)
ret = mp_set_bit(m, 0); /* force modulus odd */
/* Operands reduced to the range [0, m). */
if (ret == MP_OKAY)
ret = randNum(a, 24, rng, NULL);
if (ret == MP_OKAY)
ret = mp_mod(a, m, a);
if (ret == MP_OKAY)
ret = randNum(b, 24, rng, NULL);
if (ret == MP_OKAY)
ret = mp_mod(b, m, b);
if (ret != MP_OKAY) {
res = WC_TEST_RET_ENC_EC(ret);
break;
}
/* addmod_ct must match the variable-time addmod. */
ret = mp_addmod_ct(a, b, m, r);
if (ret == MP_OKAY)
ret = mp_addmod(a, b, m, t);
if (ret != MP_OKAY) {
res = WC_TEST_RET_ENC_EC(ret);
break;
}
if (mp_cmp(r, t) != MP_EQ) {
res = WC_TEST_RET_ENC_NC;
break;
}
/* submod_ct: (a - b) mod m, verified by adding b back gives a. */
ret = mp_submod_ct(a, b, m, r);
if (ret == MP_OKAY)
ret = mp_addmod_ct(r, b, m, t);
if (ret != MP_OKAY) {
res = WC_TEST_RET_ENC_EC(ret);
break;
}
if (mp_cmp(t, a) != MP_EQ) {
res = WC_TEST_RET_ENC_NC;
break;
}
/* div_2_mod_ct: r = a/2 mod m, verified by doubling: 2*r mod m == a. */
ret = mp_div_2_mod_ct(a, m, r);
if (ret == MP_OKAY)
ret = mp_addmod_ct(r, r, m, t);
if (ret != MP_OKAY) {
res = WC_TEST_RET_ENC_EC(ret);
break;
}
if (mp_cmp(t, a) != MP_EQ) {
res = WC_TEST_RET_ENC_NC;
break;
}
}
return res;
}
#endif /* WOLFSSL_SP_MATH_ALL && HAVE_ECC */
#if defined(WOLFSSL_SP_MATH_ALL) && !defined(WOLFSSL_RSA_PUBLIC_ONLY)
/* Exercises mp_cmp_mag - magnitude comparison (sign-independent) including
* NULL operands. */
static wc_test_ret_t mp_test_cmp_mag(mp_int* a, mp_int* b)
{
int ret;
ret = mp_set(a, 7);
if (ret == MP_OKAY)
ret = mp_set(b, 5);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
/* NULL operands: both NULL are equal, a non-NULL has greater magnitude. */
if (mp_cmp_mag(NULL, NULL) != MP_EQ)
return WC_TEST_RET_ENC_NC;
if (mp_cmp_mag(a, NULL) != MP_GT)
return WC_TEST_RET_ENC_NC;
if (mp_cmp_mag(NULL, a) != MP_LT)
return WC_TEST_RET_ENC_NC;
/* Same value and differing magnitudes. */
if (mp_cmp_mag(a, a) != MP_EQ)
return WC_TEST_RET_ENC_NC;
if (mp_cmp_mag(a, b) != MP_GT)
return WC_TEST_RET_ENC_NC;
if (mp_cmp_mag(b, a) != MP_LT)
return WC_TEST_RET_ENC_NC;
#ifdef WOLFSSL_SP_INT_NEGATIVE
/* Magnitude comparison ignores sign: |-7| > |5|. */
a->sign = MP_NEG;
if (mp_cmp_mag(a, b) != MP_GT)
return WC_TEST_RET_ENC_NC;
if (mp_cmp_mag(b, a) != MP_LT)
return WC_TEST_RET_ENC_NC;
#endif
return 0;
}
#endif /* WOLFSSL_SP_MATH_ALL && !WOLFSSL_RSA_PUBLIC_ONLY */
#if defined(WOLFSSL_SP_MATH_ALL) && !defined(WOLFSSL_RSA_VERIFY_ONLY) && \
!defined(WOLFSSL_RSA_PUBLIC_ONLY)
/* Exercises the result-aliases-modulus paths of mp_mulmod (_sp_mulmod_tmp) and
* mp_sqrmod (_sp_sqrmod), including their zero-operand short-circuits. */
static wc_test_ret_t mp_test_mulmod_sqrmod(mp_int* a, mp_int* b, mp_int* m,
mp_int* r)
{
int ret;
/* mp_mulmod with the result aliasing the modulus uses the temporary
* buffer path (_sp_mulmod_tmp). */
ret = mp_set(a, 0x3);
if (ret == MP_OKAY)
ret = mp_set(b, 0x5);
if (ret == MP_OKAY)
ret = mp_set(m, 0x65); /* modulus 101 */
if (ret == MP_OKAY)
ret = mp_mulmod(a, b, m, r); /* reference */
if (ret == MP_OKAY)
ret = mp_mulmod(a, b, m, m); /* result aliases modulus */
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
if (mp_cmp(m, r) != MP_EQ)
return WC_TEST_RET_ENC_NC;
/* Zero operand short-circuit in _sp_mulmod_tmp. */
ret = mp_set(m, 0x65);
if (ret == MP_OKAY)
ret = mp_set(b, 0);
if (ret == MP_OKAY)
ret = mp_mulmod(a, b, m, m);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
if (!mp_iszero(m))
return WC_TEST_RET_ENC_NC;
/* mp_sqrmod with the result aliasing the modulus uses _sp_sqrmod. */
ret = mp_set(a, 0x7);
if (ret == MP_OKAY)
ret = mp_set(m, 0x65);
if (ret == MP_OKAY)
ret = mp_sqrmod(a, m, r); /* reference */
if (ret == MP_OKAY)
ret = mp_set(m, 0x65);
if (ret == MP_OKAY)
ret = mp_sqrmod(a, m, m); /* result aliases modulus */
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
if (mp_cmp(m, r) != MP_EQ)
return WC_TEST_RET_ENC_NC;
/* Zero operand short-circuit in _sp_sqrmod. */
ret = mp_set(m, 0x65);
if (ret == MP_OKAY)
ret = mp_set(a, 0);
if (ret == MP_OKAY)
ret = mp_sqrmod(a, m, m);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
if (!mp_iszero(m))
return WC_TEST_RET_ENC_NC;
return 0;
}
/* Testing mp_exch. */
static wc_test_ret_t mp_test_exch(mp_int* a, mp_int* b, mp_int* r1,
mp_int* r2)
{
int ret;
/* mp_exch swaps the two values. */
ret = mp_set(a, 1);
if (ret == MP_OKAY)
ret = mp_mul_2d(a, 200, a); /* multi-word value */
if (ret == MP_OKAY)
ret = mp_add_d(a, 0x55, a);
if (ret == MP_OKAY)
ret = mp_set(b, 0x1234); /* single-word value */
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
ret = mp_copy(a, r1);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
ret = mp_copy(b, r2);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
ret = mp_exch(a, b);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
if ((mp_cmp(a, r2) != MP_EQ) || (mp_cmp(b, r1) != MP_EQ))
return WC_TEST_RET_ENC_NC;
return 0;
}
/* Testing mp_to_unsigned_bin_len_ct against the variable-time export. */
static wc_test_ret_t mp_test_to_unsigned_bin_len_ct(mp_int* a)
{
int ret;
byte buf[40];
byte buf2[40];
/* mp_to_unsigned_bin_len_ct must match the variable-time export. */
ret = mp_set(a, 1);
if (ret == MP_OKAY)
ret = mp_mul_2d(a, 100, a);
if (ret == MP_OKAY)
ret = mp_add_d(a, 0xAB, a); /* multi-word value */
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
XMEMSET(buf, 0xff, sizeof(buf));
XMEMSET(buf2, 0xff, sizeof(buf2));
ret = mp_to_unsigned_bin_len_ct(a, buf, (int)sizeof(buf));
if (ret == MP_OKAY)
ret = mp_to_unsigned_bin_len(a, buf2, (int)sizeof(buf2));
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
if (XMEMCMP(buf, buf2, sizeof(buf)) != 0)
return WC_TEST_RET_ENC_NC;
return 0;
}
#endif /* WOLFSSL_SP_MATH_ALL && !RSA_VERIFY_ONLY && !RSA_PUBLIC_ONLY */
#if (!defined(NO_RSA) && \
!defined(WOLFSSL_RSA_VERIFY_ONLY) && !defined(WOLFSSL_RSA_PUBLIC_ONLY)) || \
defined(HAVE_ECC) || !defined(NO_DSA) || defined(OPENSSL_EXTRA)
@@ -69690,9 +70137,15 @@ static wc_test_ret_t mp_test_invmod(mp_int* a, mp_int* m, mp_int* r)
#if !defined(NO_RSA) || !defined(NO_DSA) || !defined(NO_DH) || \
(defined(HAVE_ECC) && defined(HAVE_COMP_KEY)) || defined(OPENSSL_EXTRA)
static wc_test_ret_t mp_test_exptmod(mp_int* b, mp_int* e, mp_int* m, mp_int* r)
static wc_test_ret_t mp_test_exptmod(mp_int* b, mp_int* e, mp_int* m, mp_int* r,
mp_int* t)
{
wc_test_ret_t ret;
#ifdef WOLFSSL_SP_MATH_ALL
int k;
#endif
(void)t;
mp_set(b, 0x2);
mp_set(e, 0x3);
@@ -69815,6 +70268,110 @@ static wc_test_ret_t mp_test_exptmod(mp_int* b, mp_int* e, mp_int* m, mp_int* r)
return WC_TEST_RET_ENC_EC(ret);
#endif
#ifdef WOLFSSL_SP_MATH_ALL
/* Larger, multi-word moduli to exercise the Montgomery, base-2 and
* windowed exponentiation paths that small single-word moduli do not
* reach. */
/* m = 2^521 - 1 (a Mersenne prime, multi-word and not an RSA/DH
* accelerated size); e = m - 1. By Fermat's little theorem,
* b^(m-1) mod m == 1 when gcd(b, m) == 1. */
if ((ret = mp_set(m, 1)) != MP_OKAY ||
(ret = mp_mul_2d(m, 521, m)) != MP_OKAY ||
(ret = mp_sub_d(m, 1, m)) != MP_OKAY ||
(ret = mp_sub_d(m, 1, e)) != MP_OKAY) {
return WC_TEST_RET_ENC_EC(ret);
}
/* Odd, multi-word modulus, base != 2:
* mp_exptmod_ex -> constant-time Montgomery exponentiation
* mp_exptmod_nct -> windowed exponentiation (large exponent). */
if ((ret = mp_set(b, 3)) != MP_OKAY ||
(ret = mp_exptmod_ex(b, e, (int)e->used, m, r)) != MP_OKAY) {
return WC_TEST_RET_ENC_EC(ret);
}
if (!mp_isone(r)) {
return WC_TEST_RET_ENC_NC;
}
if ((ret = mp_exptmod_nct(b, e, m, r)) != MP_OKAY) {
return WC_TEST_RET_ENC_EC(ret);
}
if (!mp_isone(r)) {
return WC_TEST_RET_ENC_NC;
}
/* Base 2 selects the dedicated base-2 exponentiation. */
if ((ret = mp_set(b, 2)) != MP_OKAY ||
(ret = mp_exptmod_ex(b, e, (int)e->used, m, r)) != MP_OKAY) {
return WC_TEST_RET_ENC_EC(ret);
}
if (!mp_isone(r)) {
return WC_TEST_RET_ENC_NC;
}
/* Smaller exponents reach the narrower window sizes of the windowed
* non-constant-time exponentiation (a 31-bit exponent uses a 3-bit
* window, a 101-bit exponent a 4-bit window). Cross-check the
* windowed result against the constant-time Montgomery result. */
for (k = 0; k < 2; k++) {
int ebits = (k == 0) ? 30 : 100;
if ((ret = mp_set(e, 1)) != MP_OKAY ||
(ret = mp_mul_2d(e, ebits, e)) != MP_OKAY ||
(ret = mp_add_d(e, 0x9, e)) != MP_OKAY || /* odd exponent */
(ret = mp_set(b, 3)) != MP_OKAY ||
(ret = mp_exptmod_ex(b, e, (int)e->used, m, r)) != MP_OKAY ||
(ret = mp_exptmod_nct(b, e, m, t)) != MP_OKAY) {
return WC_TEST_RET_ENC_EC(ret);
}
if (mp_cmp(r, t) != MP_EQ) {
return WC_TEST_RET_ENC_NC;
}
}
/* Restore exponent to m - 1 for the remaining odd-modulus case. */
if ((ret = mp_sub_d(m, 1, e)) != MP_OKAY) {
return WC_TEST_RET_ENC_EC(ret);
}
/* Base == modulus: base reduces to zero so the result is zero. */
if ((ret = mp_copy(m, b)) != MP_OKAY ||
(ret = mp_set(e, 5)) != MP_OKAY ||
(ret = mp_exptmod_ex(b, e, (int)e->used, m, r)) != MP_OKAY) {
return WC_TEST_RET_ENC_EC(ret);
}
if (!mp_iszero(r)) {
return WC_TEST_RET_ENC_NC;
}
/* Even, multi-word modulus uses the generic exponentiation path for
* both mp_exptmod_ex and mp_exptmod_nct. Verify b^6 mod m against
* repeated modular multiplication. */
if ((ret = mp_set(m, 1)) != MP_OKAY ||
(ret = mp_mul_2d(m, 521, m)) != MP_OKAY || /* m = 2^521 (even) */
(ret = mp_set(b, 7)) != MP_OKAY ||
(ret = mp_set(e, 6)) != MP_OKAY ||
(ret = mp_set(t, 1)) != MP_OKAY) {
return WC_TEST_RET_ENC_EC(ret);
}
for (k = 0; k < 6; k++) {
if ((ret = mp_mulmod(t, b, m, t)) != MP_OKAY) {
return WC_TEST_RET_ENC_EC(ret);
}
}
if ((ret = mp_exptmod_ex(b, e, (int)e->used, m, r)) != MP_OKAY) {
return WC_TEST_RET_ENC_EC(ret);
}
if (mp_cmp(r, t) != MP_EQ) {
return WC_TEST_RET_ENC_NC;
}
if ((ret = mp_exptmod_nct(b, e, m, r)) != MP_OKAY) {
return WC_TEST_RET_ENC_EC(ret);
}
if (mp_cmp(r, t) != MP_EQ) {
return WC_TEST_RET_ENC_NC;
}
#endif /* WOLFSSL_SP_MATH_ALL */
return 0;
}
#endif /* !NO_RSA || !NO_DSA || !NO_DH || (HAVE_ECC && HAVE_COMP_KEY) ||
@@ -69936,6 +70493,41 @@ static wc_test_ret_t mp_test_mont(mp_int* a, mp_int* m, mp_int* n, mp_int* r, WC
return WC_TEST_RET_ENC_NC;
}
#ifdef WOLFSSL_SP_INVMOD_MONT_CT
/* Constant-time modular inverse in Montgomery form over a multi-word
* prime exercises the table-based exponentiation in _sp_invmod_mont_ct
* that single-word moduli do not reach. */
/* m = 2^521 - 1 (a Mersenne prime, multi-word). */
ret = mp_2expt(m, 521);
if (ret == MP_OKAY)
ret = mp_sub_d(m, 1, m);
if (ret == MP_OKAY)
ret = mp_montgomery_setup(m, &mp);
if (ret == MP_OKAY)
ret = mp_montgomery_calc_normalization(n, m);
/* a = 5: non-zero and coprime to the prime modulus. */
if (ret == MP_OKAY)
ret = mp_set(a, 5);
/* n = a in Montgomery form (a * R mod m). */
if (ret == MP_OKAY)
ret = mp_mulmod(a, n, m, n);
/* r = a^-1 in Montgomery form. */
if (ret == MP_OKAY)
ret = mp_invmod_mont_ct(n, m, r, mp);
/* Take r out of Montgomery form: r = a^-1 mod m. */
if (ret == MP_OKAY)
ret = mp_montgomery_reduce(r, m, mp);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
/* Verify a * a^-1 mod m == 1. */
ret = mp_mulmod(a, r, m, n);
if (ret != MP_OKAY)
return WC_TEST_RET_ENC_EC(ret);
if (!mp_isone(n))
return WC_TEST_RET_ENC_NC;
#endif /* WOLFSSL_SP_INVMOD_MONT_CT */
return 0;
}
#endif
@@ -70237,7 +70829,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t mp_test(void)
goto done;
#if !(defined(WOLFSSL_SP_MATH_ALL) || defined(WOLFSSL_SP_MATH)) || \
(defined(WOLFSSL_SP_ADD_D) && defined(WOLFSSL_SP_SUB_D))
if ((ret = mp_test_add_sub_d(a, r1)) != 0)
if ((ret = mp_test_add_sub_d(a, b, r1)) != 0)
goto done;
#endif
if ((ret = mp_test_read_to_bin(a)) != 0)
@@ -70267,7 +70859,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t mp_test(void)
if ((ret = mp_test_prime(a, &rng)) != 0)
goto done;
#endif
#if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && !defined(WC_RSA_BLINDING)
#if !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN)
if ((ret = mp_test_lcm_gcd(a, b, r1, r2, &rng)) != 0)
goto done;
#endif
@@ -70291,7 +70883,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t mp_test(void)
#endif
#if !defined(NO_RSA) || !defined(NO_DSA) || !defined(NO_DH) || \
(defined(HAVE_ECC) && defined(HAVE_COMP_KEY)) || defined(OPENSSL_EXTRA)
if ((ret = mp_test_exptmod(a, b, r1, r2)) != 0)
if ((ret = mp_test_exptmod(a, b, r1, r2, p)) != 0)
goto done;
#endif
#if defined(HAVE_ECC) || \
@@ -70299,6 +70891,23 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t mp_test(void)
if ((ret = mp_test_mont(a, b, r1, r2, &rng)) != 0)
goto done;
#endif
#if defined(WOLFSSL_SP_MATH_ALL) && defined(HAVE_ECC)
if ((ret = mp_test_addsubmod_ct(a, b, r1, r2, p, &rng)) != 0)
goto done;
#endif
#if defined(WOLFSSL_SP_MATH_ALL) && !defined(WOLFSSL_RSA_PUBLIC_ONLY)
if ((ret = mp_test_cmp_mag(a, b)) != 0)
goto done;
#endif
#if defined(WOLFSSL_SP_MATH_ALL) && !defined(WOLFSSL_RSA_VERIFY_ONLY) && \
!defined(WOLFSSL_RSA_PUBLIC_ONLY)
if ((ret = mp_test_mulmod_sqrmod(a, b, p, r1)) != 0)
goto done;
if ((ret = mp_test_exch(a, b, r1, r2)) != 0)
goto done;
if ((ret = mp_test_to_unsigned_bin_len_ct(a)) != 0)
goto done;
#endif
#ifdef MP_TEST_COND_SWAP_AVAILABLE
if ((ret = mp_test_cond_swap(a, b)) != 0)
goto done;