add feature detection macro MP_HAS

This commit is contained in:
Daniel Mendler 2019-04-08 23:48:39 +02:00
parent 584405ff8e
commit 8c1b296e86
No known key found for this signature in database
GPG Key ID: D88ADB2A2693CA43
13 changed files with 199 additions and 242 deletions

View File

@ -43,12 +43,10 @@ mp_err mp_div_d(const mp_int *a, mp_digit b, mp_int *c, mp_digit *d)
return MP_OKAY;
}
#ifdef BN_MP_DIV_3_C
/* three? */
if (b == 3u) {
if (MP_HAS(MP_DIV_3) && b == 3u) {
return mp_div_3(a, c, d);
}
#endif
/* no easy answer [c'est la vie]. Just division */
if ((err = mp_init_size(&q, a->used)) != MP_OKAY) {

View File

@ -19,10 +19,13 @@ mp_err mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y)
/* if exponent X is negative we have to recurse */
if (X->sign == MP_NEG) {
#ifdef BN_MP_INVMOD_C
mp_int tmpG, tmpX;
mp_err err;
if (!MP_HAS(MP_INVMOD)) {
return MP_VAL;
}
/* first compute 1/G mod P */
if ((err = mp_init(&tmpG)) != MP_OKAY) {
return err;
@ -46,50 +49,32 @@ mp_err mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y)
err = mp_exptmod(&tmpG, &tmpX, P, Y);
mp_clear_multi(&tmpG, &tmpX, NULL);
return err;
#else
/* no invmod */
return MP_VAL;
#endif
}
/* modified diminished radix reduction */
#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C)
if (mp_reduce_is_2k_l(P) == MP_YES) {
if (MP_HAS(MP_REDUCE_IS_2K_L) && MP_HAS(MP_REDUCE_2K_L) && MP_HAS(S_MP_EXPTMOD) &&
mp_reduce_is_2k_l(P) == MP_YES) {
return s_mp_exptmod(G, X, P, Y, 1);
}
#endif
#ifdef BN_MP_DR_IS_MODULUS_C
/* is it a DR modulus? */
dr = (mp_dr_is_modulus(P) == MP_YES) ? 1 : 0;
#else
/* default to no */
dr = 0;
#endif
/* is it a DR modulus? default to no */
dr = MP_HAS(MP_DR_IS_MODULUS) && mp_dr_is_modulus(P) == MP_YES ? 1 : 0;
#ifdef BN_MP_REDUCE_IS_2K_C
/* if not, is it a unrestricted DR modulus? */
if (dr == 0) {
if (MP_HAS(MP_REDUCE_IS_2K) && dr == 0) {
dr = (mp_reduce_is_2k(P) == MP_YES) ? 2 : 0;
}
#endif
/* if the modulus is odd or dr != 0 use the montgomery method */
#ifdef BN_S_MP_EXPTMOD_FAST_C
if (MP_IS_ODD(P) || (dr != 0)) {
if (MP_HAS(S_MP_EXPTMOD_FAST) && (MP_IS_ODD(P) || (dr != 0))) {
return s_mp_exptmod_fast(G, X, P, Y, dr);
} else {
#endif
#ifdef BN_S_MP_EXPTMOD_C
} else if (MP_HAS(S_MP_EXPTMOD)) {
/* otherwise use the generic Barrett reduction technique */
return s_mp_exptmod(G, X, P, Y, 0);
#else
} else {
/* no exptmod for evens */
return MP_VAL;
#endif
#ifdef BN_S_MP_EXPTMOD_FAST_C
}
#endif
}
#endif

View File

@ -11,17 +11,13 @@ mp_err mp_invmod(const mp_int *a, const mp_int *b, mp_int *c)
return MP_VAL;
}
#ifdef BN_S_MP_INVMOD_FAST_C
/* if the modulus is odd we can use a faster routine instead */
if (MP_IS_ODD(b)) {
if (MP_HAS(S_MP_INVMOD_FAST) && MP_IS_ODD(b)) {
return s_mp_invmod_fast(a, b, c);
}
#endif
#ifdef BN_S_MP_INVMOD_SLOW_C
return s_mp_invmod_slow(a, b, c);
#else
return MP_VAL;
#endif
return MP_HAS(S_MP_INVMOD_SLOW)
? s_mp_invmod_slow(a, b, c)
: MP_VAL;
}
#endif

View File

@ -7,79 +7,45 @@
mp_err mp_mul(const mp_int *a, const mp_int *b, mp_int *c)
{
mp_err err;
mp_sign neg;
#ifdef BN_S_MP_BALANCE_MUL_C
int len_b, len_a;
#endif
neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
#ifdef BN_S_MP_BALANCE_MUL_C
len_a = a->used;
len_b = b->used;
int min_len = MP_MIN(a->used, b->used),
max_len = MP_MAX(a->used, b->used),
digs = a->used + b->used + 1;
mp_sign neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
if (len_a == len_b) {
goto GO_ON;
}
/*
* Check sizes. The smaller one needs to be larger than the Karatsuba cut-off.
* The bigger one needs to be at least about one KARATSUBA_MUL_CUTOFF bigger
if (MP_HAS(S_MP_BALANCE_MUL) &&
/* Check sizes. The smaller one needs to be larger than the Karatsuba cut-off.
* The bigger one needs to be at least about one MP_KARATSUBA_MUL_CUTOFF bigger
* to make some sense, but it depends on architecture, OS, position of the
* stars... so YMMV.
* Using it to cut the input into slices small enough for fast_s_mp_mul_digs
* was actually slower on the author's machine, but YMMV.
*/
if ((MP_MIN(len_a, len_b) < MP_KARATSUBA_MUL_CUTOFF)
|| ((MP_MAX(len_a, len_b) / 2) < MP_KARATSUBA_MUL_CUTOFF)) {
goto GO_ON;
}
/*
* Not much effect was observed below a ratio of 1:2, but again: YMMV.
*/
if ((MP_MAX(len_a, len_b) / MP_MIN(len_a, len_b)) < 2) {
goto GO_ON;
}
(min_len >= MP_KARATSUBA_MUL_CUTOFF) &&
(max_len / 2 >= MP_KARATSUBA_MUL_CUTOFF) &&
/* Not much effect was observed below a ratio of 1:2, but again: YMMV. */
(max_len >= (2 * min_len))) {
err = s_mp_balance_mul(a,b,c);
goto END;
GO_ON:
#endif
/* use Toom-Cook? */
#ifdef BN_S_MP_TOOM_MUL_C
if (MP_MIN(a->used, b->used) >= MP_TOOM_MUL_CUTOFF) {
} else if (MP_HAS(S_MP_TOOM_MUL) &&
(min_len >= MP_TOOM_MUL_CUTOFF)) {
err = s_mp_toom_mul(a, b, c);
} else
#endif
#ifdef BN_S_MP_KARATSUBA_MUL_C
/* use Karatsuba? */
if (MP_MIN(a->used, b->used) >= MP_KARATSUBA_MUL_CUTOFF) {
} else if (MP_HAS(S_MP_KARATSUBA_MUL) &&
(min_len >= MP_KARATSUBA_MUL_CUTOFF)) {
err = s_mp_karatsuba_mul(a, b, c);
} else
#endif
{
} else if (MP_HAS(S_MP_MUL_DIGS_FAST) &&
/* can we use the fast multiplier?
*
* The fast multiplier can be used if the output will
* have less than MP_WARRAY digits and the number of
* digits won't affect carry propagation
*/
int digs = a->used + b->used + 1;
#ifdef BN_S_MP_MUL_DIGS_FAST_C
if ((digs < MP_WARRAY) &&
(MP_MIN(a->used, b->used) <= MP_MAXFAST)) {
(digs < MP_WARRAY) &&
(min_len <= MP_MAXFAST)) {
err = s_mp_mul_digs_fast(a, b, c, digs);
} else
#endif
{
#ifdef BN_S_MP_MUL_DIGS_C
err = s_mp_mul_digs(a, b, c, a->used + b->used + 1);
#else
} else if (MP_HAS(S_MP_MUL_DIGS)) {
err = s_mp_mul_digs(a, b, c, digs);
} else {
err = MP_VAL;
#endif
}
}
END:
c->sign = (c->used > 0) ? neg : MP_ZPOS;
return err;
}

View File

@ -26,22 +26,18 @@ mp_err mp_reduce(mp_int *x, const mp_int *m, const mp_int *mu)
if ((err = mp_mul(&q, mu, &q)) != MP_OKAY) {
goto CLEANUP;
}
} else {
#ifdef BN_S_MP_MUL_HIGH_DIGS_C
} else if (MP_HAS(S_MP_MUL_HIGH_DIGS)) {
if ((err = s_mp_mul_high_digs(&q, mu, &q, um)) != MP_OKAY) {
goto CLEANUP;
}
#elif defined(BN_S_MP_MUL_HIGH_DIGS_FAST_C)
} else if (MP_HAS(S_MP_MUL_HIGH_DIGS_FAST)) {
if ((err = s_mp_mul_high_digs_fast(&q, mu, &q, um)) != MP_OKAY) {
goto CLEANUP;
}
#else
{
} else {
err = MP_VAL;
goto CLEANUP;
}
#endif
}
/* q3 = q2 / b**(k+1) */
mp_rshd(&q, um + 1);

View File

@ -7,34 +7,20 @@
mp_err mp_sqr(const mp_int *a, mp_int *b)
{
mp_err err;
#ifdef BN_S_MP_TOOM_SQR_C
/* use Toom-Cook? */
if (a->used >= MP_TOOM_SQR_CUTOFF) {
if (MP_HAS(S_MP_TOOM_SQR) && /* use Toom-Cook? */
a->used >= MP_TOOM_SQR_CUTOFF) {
err = s_mp_toom_sqr(a, b);
/* Karatsuba? */
} else
#endif
#ifdef BN_S_MP_KARATSUBA_SQR_C
if (a->used >= MP_KARATSUBA_SQR_CUTOFF) {
} else if (MP_HAS(S_MP_KARATSUBA_SQR) && /* Karatsuba? */
a->used >= MP_KARATSUBA_SQR_CUTOFF) {
err = s_mp_karatsuba_sqr(a, b);
} else
#endif
{
#ifdef BN_S_MP_SQR_FAST_C
/* can we use the fast comba multiplier? */
if ((((a->used * 2) + 1) < MP_WARRAY) &&
} else if (MP_HAS(S_MP_SQR_FAST) && /* can we use the fast comba multiplier? */
(((a->used * 2) + 1) < MP_WARRAY) &&
(a->used < (MP_MAXFAST / 2))) {
err = s_mp_sqr_fast(a, b);
} else
#endif
{
#ifdef BN_S_MP_SQR_C
} else if (MP_HAS(S_MP_SQR)) {
err = s_mp_sqr(a, b);
#else
} else {
err = MP_VAL;
#endif
}
}
b->sign = MP_ZPOS;
return err;

View File

@ -5,8 +5,10 @@
#ifdef MP_LOW_MEM
# define TAB_SIZE 32
# define MAX_WINSIZE 5
#else
# define TAB_SIZE 256
# define MAX_WINSIZE 0
#endif
mp_err s_mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode)
@ -35,11 +37,7 @@ mp_err s_mp_exptmod(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y
winsize = 8;
}
#ifdef MP_LOW_MEM
if (winsize > 5) {
winsize = 5;
}
#endif
winsize = MAX_WINSIZE ? MP_MIN(MAX_WINSIZE, winsize) : winsize;
/* init M array */
/* init first cell */

View File

@ -13,8 +13,10 @@
#ifdef MP_LOW_MEM
# define TAB_SIZE 32
# define MAX_WINSIZE 5
#else
# define TAB_SIZE 256
# define MAX_WINSIZE 0
#endif
mp_err s_mp_exptmod_fast(const mp_int *G, const mp_int *X, const mp_int *P, mp_int *Y, int redmode)
@ -48,11 +50,7 @@ mp_err s_mp_exptmod_fast(const mp_int *G, const mp_int *X, const mp_int *P, mp_i
winsize = 8;
}
#ifdef MP_LOW_MEM
if (winsize > 5) {
winsize = 5;
}
#endif
winsize = MAX_WINSIZE ? MP_MIN(MAX_WINSIZE, winsize) : winsize;
/* init M array */
/* init first cell */
@ -73,52 +71,46 @@ mp_err s_mp_exptmod_fast(const mp_int *G, const mp_int *X, const mp_int *P, mp_i
/* determine and setup reduction code */
if (redmode == 0) {
#ifdef BN_MP_MONTGOMERY_SETUP_C
if (MP_HAS(MP_MONTGOMERY_SETUP)) {
/* now setup montgomery */
if ((err = mp_montgomery_setup(P, &mp)) != MP_OKAY) {
goto LBL_M;
}
#else
} else {
err = MP_VAL;
goto LBL_M;
#endif
}
/* automatically pick the comba one if available (saves quite a few calls/ifs) */
#ifdef BN_S_MP_MONTGOMERY_REDUCE_FAST_C
if ((((P->used * 2) + 1) < MP_WARRAY) &&
if (MP_HAS(S_MP_MONTGOMERY_REDUCE_FAST) &&
(((P->used * 2) + 1) < MP_WARRAY) &&
(P->used < MP_MAXFAST)) {
redux = s_mp_montgomery_reduce_fast;
} else
#endif
{
#ifdef BN_MP_MONTGOMERY_REDUCE_C
} else if (MP_HAS(MP_MONTGOMERY_REDUCE)) {
/* use slower baseline Montgomery method */
redux = mp_montgomery_reduce;
#else
} else {
err = MP_VAL;
goto LBL_M;
#endif
}
} else if (redmode == 1) {
#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C)
if (MP_HAS(MP_DR_SETUP) && MP_HAS(MP_DR_REDUCE)) {
/* setup DR reduction for moduli of the form B**k - b */
mp_dr_setup(P, &mp);
redux = mp_dr_reduce;
#else
} else {
err = MP_VAL;
goto LBL_M;
#endif
} else {
#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C)
}
} else if (MP_HAS(MP_REDUCE_2K_SETUP) && MP_HAS(MP_REDUCE_2K)) {
/* setup DR reduction for moduli of the form 2**k - b */
if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) {
goto LBL_M;
}
redux = mp_reduce_2k;
#else
} else {
err = MP_VAL;
goto LBL_M;
#endif
}
/* setup result */
@ -134,7 +126,7 @@ mp_err s_mp_exptmod_fast(const mp_int *G, const mp_int *X, const mp_int *P, mp_i
*/
if (redmode == 0) {
#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
if (MP_HAS(MP_MONTGOMERY_CALC_NORMALIZATION)) {
/* now we need R mod m */
if ((err = mp_montgomery_calc_normalization(&res, P)) != MP_OKAY) {
goto LBL_RES;
@ -144,10 +136,10 @@ mp_err s_mp_exptmod_fast(const mp_int *G, const mp_int *X, const mp_int *P, mp_i
if ((err = mp_mulmod(G, &res, P, &M[1])) != MP_OKAY) {
goto LBL_RES;
}
#else
} else {
err = MP_VAL;
goto LBL_RES;
#endif
}
} else {
mp_set(&res, 1uL);
if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) {

View File

@ -16,12 +16,11 @@ mp_err s_mp_mul_high_digs(const mp_int *a, const mp_int *b, mp_int *c, int digs)
mp_digit tmpx, *tmpt, *tmpy;
/* can we use the fast multiplier? */
#ifdef BN_S_MP_MUL_HIGH_DIGS_FAST_C
if (((a->used + b->used + 1) < MP_WARRAY)
if (MP_HAS(S_MP_MUL_HIGH_DIGS_FAST)
&& ((a->used + b->used + 1) < MP_WARRAY)
&& (MP_MIN(a->used, b->used) < MP_MAXFAST)) {
return s_mp_mul_high_digs_fast(a, b, c, digs);
}
#endif
if ((err = mp_init_size(&t, a->used + b->used + 1)) != MP_OKAY) {
return err;

View File

@ -8,11 +8,16 @@
* - Windows
*/
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
# define MP_ARC4RANDOM
#define BN_S_READ_ARC4RANDOM_C
static mp_err s_read_arc4random(void *p, size_t n)
{
arc4random_buf(p, n);
return MP_OKAY;
}
#endif
#if defined(_WIN32) || defined(_WIN32_WCE)
#define MP_WIN_CSP
#define BN_S_READ_WINCSP_C
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
@ -33,7 +38,7 @@
# pragma warning(pop)
#endif
static mp_err s_read_win_csp(void *p, size_t n)
static mp_err s_read_wincsp(void *p, size_t n)
{
static HCRYPTPROV hProv = 0;
if (hProv == 0) {
@ -50,9 +55,9 @@ static mp_err s_read_win_csp(void *p, size_t n)
}
#endif /* WIN32 */
#if !defined(MP_WIN_CSP) && defined(__linux__) && defined(__GLIBC_PREREQ)
#if !defined(BN_S_READ_WINCSP_C) && defined(__linux__) && defined(__GLIBC_PREREQ)
#if __GLIBC_PREREQ(2, 25)
#define MP_GETRANDOM
#define BN_S_READ_GETRANDOM_C
#include <sys/random.h>
#include <errno.h>
@ -78,7 +83,8 @@ static mp_err s_read_getrandom(void *p, size_t n)
/* We assume all platforms besides windows provide "/dev/urandom".
* In case yours doesn't, define MP_NO_DEV_URANDOM at compile-time.
*/
#if !defined(MP_WIN_CSP) && !defined(MP_NO_DEV_URANDOM)
#if !defined(BN_S_READ_WINCSP_C) && !defined(MP_NO_DEV_URANDOM)
#define BN_S_READ_URANDOM_C
#ifndef MP_DEV_URANDOM
#define MP_DEV_URANDOM "/dev/urandom"
#endif
@ -86,7 +92,7 @@ static mp_err s_read_getrandom(void *p, size_t n)
#include <errno.h>
#include <unistd.h>
static mp_err s_read_dev_urandom(void *p, size_t n)
static mp_err s_read_urandom(void *p, size_t n)
{
int fd;
char *q = (char *)p;
@ -115,6 +121,7 @@ static mp_err s_read_dev_urandom(void *p, size_t n)
#endif
#if defined(MP_PRNG_ENABLE_LTM_RNG)
#define B_S_READ_LTM_RNG
unsigned long (*ltm_rng)(unsigned char *out, unsigned long outlen, void (*callback)(void));
void (*ltm_rng_callback)(void);
@ -128,37 +135,21 @@ static mp_err s_read_ltm_rng(void *p, size_t n)
}
#endif
mp_err s_read_arc4random(void *p, size_t n);
mp_err s_read_wincsp(void *p, size_t n);
mp_err s_read_getrandom(void *p, size_t n);
mp_err s_read_urandom(void *p, size_t n);
mp_err s_read_ltm_rng(void *p, size_t n);
mp_err s_mp_rand_platform(void *p, size_t n)
{
#if defined(MP_ARC4RANDOM)
arc4random_buf(p, n);
return MP_OKAY;
#else
mp_err res = MP_ERR;
#if defined(MP_WIN_CSP)
res = s_read_win_csp(p, n);
if (res == MP_OKAY) return res;
#endif
#if defined(MP_GETRANDOM)
res = s_read_getrandom(p, n);
if (res == MP_OKAY) return res;
#endif
#if defined(MP_DEV_URANDOM)
res = s_read_dev_urandom(p, n);
if (res == MP_OKAY) return res;
#endif
#if defined(MP_PRNG_ENABLE_LTM_RNG)
res = s_read_ltm_rng(p, n);
if (res == MP_OKAY) return res;
#endif
return res;
#endif
mp_err err = MP_ERR;
if ((err != MP_OKAY) && MP_HAS(S_READ_ARC4RANDOM)) err = s_read_arc4random(p, n);
if ((err != MP_OKAY) && MP_HAS(S_READ_WINCSP)) err = s_read_wincsp(p, n);
if ((err != MP_OKAY) && MP_HAS(S_READ_GETRANDOM)) err = s_read_getrandom(p, n);
if ((err != MP_OKAY) && MP_HAS(S_READ_URANDOM)) err = s_read_urandom(p, n);
if ((err != MP_OKAY) && MP_HAS(S_READ_LTM_RNG)) err = s_read_ltm_rng(p, n);
return err;
}
#endif

View File

@ -50,6 +50,49 @@ static uint64_t uabs64(int64_t x)
return x > 0 ? (uint64_t)x : -(uint64_t)x;
}
/* This function prototype is needed
* to test dead code elimination
* which is used for feature detection.
*
* If the feature detection does not
* work as desired we will get a linker error.
*/
void does_not_exist(void);
static int test_feature_detection(void)
{
#define BN_TEST_FEATURE1_C
if (!MP_HAS(TEST_FEATURE1)) {
does_not_exist();
return EXIT_FAILURE;
}
#define BN_TEST_FEATURE2_C 1
if (MP_HAS(TEST_FEATURE2)) {
does_not_exist();
return EXIT_FAILURE;
}
#define BN_TEST_FEATURE3_C 0
if (MP_HAS(TEST_FEATURE3)) {
does_not_exist();
return EXIT_FAILURE;
}
#define BN_TEST_FEATURE4_C something
if (MP_HAS(TEST_FEATURE4)) {
does_not_exist();
return EXIT_FAILURE;
}
if (MP_HAS(TEST_FEATURE5)) {
does_not_exist();
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
static int test_trivial_stuff(void)
{
mp_int a, b, c, d;
@ -2046,6 +2089,7 @@ int unit_tests(int argc, char **argv)
int (*fn)(void);
} test[] = {
#define T(n) { #n, test_##n }
T(feature_detection),
T(trivial_stuff),
T(mp_get_set_i32),
T(mp_get_set_i64),

View File

@ -860,6 +860,7 @@
# define BN_MP_SUB_C
# define BN_S_MP_MUL_DIGS_C
# define BN_S_MP_MUL_HIGH_DIGS_C
# define BN_S_MP_MUL_HIGH_DIGS_FAST_C
# define BN_S_MP_SUB_C
#endif

View File

@ -140,6 +140,11 @@ extern void *MP_CALLOC(size_t nmemb, size_t size);
extern void MP_FREE(void *mem, size_t size);
#endif
/* feature detection macro */
#define MP_STRINGIZE(x) MP__STRINGIZE(x)
#define MP__STRINGIZE(x) ""#x""
#define MP_HAS(x) (sizeof(MP_STRINGIZE(BN_##x##_C)) == 1)
/* TODO: Remove private_mp_word as soon as deprecated mp_word is removed from tommath. */
#undef mp_word
typedef private_mp_word mp_word;