From fdbd6addd0af08350e11e4d07da1ff9c67824351 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Fri, 4 Sep 2020 23:17:17 -0500 Subject: [PATCH] sp_int.c: add sp_mod_word() gated on WOLFSSL_SP_MOD_WORD_RP for runtimes lacking intrinsic support for int128 % int64; for linuxkm, use WOLFSSL_SP_DIV_WORD_HALF and the new WOLFSSL_SP_MOD_WORD_RP. --- wolfcrypt/src/sp_int.c | 85 +++++++++++++++++++++++++++++++----- wolfssl/wolfcrypt/settings.h | 6 ++- 2 files changed, 78 insertions(+), 13 deletions(-) diff --git a/wolfcrypt/src/sp_int.c b/wolfcrypt/src/sp_int.c index 00d7d87dc..a2fa7f6c3 100644 --- a/wolfcrypt/src/sp_int.c +++ b/wolfcrypt/src/sp_int.c @@ -808,11 +808,7 @@ static WC_INLINE sp_int_digit sp_div_word(sp_int_digit hi, sp_int_digit lo, sp_int_digit r; w = ((sp_int_word)hi << SP_WORD_SIZE) | lo; -#ifdef WOLFSSL_LINUXKM - do_div(w, d); -#else w /= d; -#endif r = (sp_int_digit)w; return r; @@ -1471,9 +1467,73 @@ int sp_mulmod(sp_int* a, sp_int* b, sp_int* m, sp_int* r) } #endif +#ifdef WOLFSSL_SP_MOD_WORD_RP +/* Calculate the word w modulo the digit d into r: r = w mod d + * + * w SP integer word, dividend and result. + * d SP integer digit, modulus. + * + * returns MP_VAL when d is 0 and MP_OKAY otherwise. + */ +static WC_INLINE int sp_mod_word(sp_int_word *w, sp_int_digit d) { + sp_int_word x; + int x_shift; + if (*w == 0) + return 0; + if (d == 0) + return MP_VAL; + + /* Russian Peasant algorithm for division, optimized: + * + * first, shift x leftward just enough to be greater than w/2. + * this can be done by counting the leading zeros of each, + * shifting so that x has one less leading zero, and then doing a + * final comparison. + * + * textbook logic: + * + * while (x <= w/2) + * x <<= 1; + */ + x_shift = ((int)__builtin_clzll(d) + (SP_WORD_SIZE - 1)); + if ((*w >> SP_WORD_SIZE) == 0) + x_shift -= +#if SP_WORD_SIZE == 64 + (int)__builtin_clzll((uint64_t)*w) +#elif SP_WORD_SIZE == 32 + (int)__builtin_clz((uint32_t)*w) +#else +#error unexpected SP_WORD_SIZE +#endif + + SP_WORD_SIZE; + else + x_shift -= +#if SP_WORD_SIZE == 64 + (int)__builtin_clzll((uint64_t)(*w >> SP_WORD_SIZE)) +#elif SP_WORD_SIZE == 32 + (int)__builtin_clz((uint32_t)(*w >> SP_WORD_SIZE)) +#else +#error unexpected SP_WORD_SIZE +#endif + ; + if (x_shift < 0) + x_shift = 0; + x = (sp_int_word)d << x_shift; + if (x <= (*w>>1)) + x <<= 1; + + while (*w >= (sp_int_word)d) { + if (*w >= x) + *w -= x; + x >>= 1; + } + return MP_OKAY; +} +#endif /* WOLFSSL_SP_MOD_WORD_RP */ + /* Calculate a modulo the digit d into r: r = a mod d * - * a SP integer to square. + * a SP integer, dividend. * d SP integer digit, modulus. * r SP integer digit, result. * returns MP_VAL when d is 0 and MP_OKAY otherwise. @@ -1483,7 +1543,6 @@ static int sp_mod_d(sp_int* a, const sp_int_digit d, sp_int_digit* r) int err = MP_OKAY; int i; sp_int_word w = 0; - sp_int_digit t; if (d == 0) err = MP_VAL; @@ -1491,13 +1550,17 @@ static int sp_mod_d(sp_int* a, const sp_int_digit d, sp_int_digit* r) if (err == MP_OKAY) { for (i = a->used - 1; i >= 0; i--) { w = (w << SP_WORD_SIZE) | a->dp[i]; -#ifdef WOLFSSL_LINUXKM - t = (sp_int_digit)w; - do_div(t, d); +#ifdef WOLFSSL_SP_MOD_WORD_RP + if (sp_mod_word(&w, d) == MP_VAL) { + err = MP_VAL; + break; + } #else - t = (sp_int_digit)(w / d); + { + sp_int_digit t = (sp_int_digit)(w / d); + w -= (sp_int_word)t * d; + } #endif - w -= (sp_int_word)t * d; } *r = (sp_int_digit)w; diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 10c54f9fe..8207b3e83 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -2093,8 +2093,6 @@ extern void uITRON4_free(void *p) ; #define SIZEOF_LONG 8 #define SIZEOF_LONG_LONG 8 #define CHAR_BIT 8 - - /* tweak the autotools-detected feature set to accommodate switch from user to kernel space: */ #undef HAVE_STRINGS_H #undef HAVE_ERRNO_H #undef HAVE_THREAD_LS @@ -2105,6 +2103,10 @@ extern void uITRON4_free(void *p) ; #define WOLFSSL_USER_IO #define USE_WOLF_STRTOK #define WOLFSSL_SP_DIV_64 + #define WOLFSSL_SP_DIV_WORD_HALF + #define SP_HALF_SIZE 32 + #define SP_HALF_MAX 4294967295U + #define WOLFSSL_SP_MOD_WORD_RP #define WOLFSSL_OLD_PRIME_CHECK #endif