diff --git a/makefile b/makefile index ffcd8bf..12af1b8 100644 --- a/makefile +++ b/makefile @@ -53,7 +53,8 @@ src/sqr/fp_sqr.o src/sqr/fp_sqr_comba.o src/sqr/fp_sqr_comba_12.o src/sqr/fp_sqr src/sqr/fp_sqr_comba_20.o src/sqr/fp_sqr_comba_24.o src/sqr/fp_sqr_comba_28.o src/sqr/fp_sqr_comba_3.o \ src/sqr/fp_sqr_comba_32.o src/sqr/fp_sqr_comba_4.o src/sqr/fp_sqr_comba_48.o src/sqr/fp_sqr_comba_6.o \ src/sqr/fp_sqr_comba_64.o src/sqr/fp_sqr_comba_7.o src/sqr/fp_sqr_comba_8.o src/sqr/fp_sqr_comba_9.o \ -src/sqr/fp_sqr_comba_generic.o src/sqr/fp_sqr_comba_small_set.o src/sqr/fp_sqrmod.o +src/sqr/fp_sqr_comba_generic.o src/sqr/fp_sqr_comba_small_set.o src/sqr/fp_sqrmod.o \ +src/misc/fp_memcpy.o src/misc/fp_memset.o HEADERS_PUB=src/headers/tfm.h HEADERS=src/headers/tfm_private.h $(HEADERS_PUB) diff --git a/src/headers/tfm.h b/src/headers/tfm.h index 3ed7f89..6c47a33 100644 --- a/src/headers/tfm.h +++ b/src/headers/tfm.h @@ -9,11 +9,26 @@ #ifndef TFM_H_ #define TFM_H_ +#if TFM_NO_STDLIB +/* do nothing */ +#elif defined(TFM_NO_STDLIB) +/* defined but false, make sure `#ifdef TFM_NO_STDLIB` works */ +#undef TFM_NO_STDLIB +#elif (defined(__wasm) || defined(__wasm__) || defined(__WASM__)) +/* disable stdlib by default for web assembly */ +#define TFM_NO_STDLIB +#endif + +#include +#ifndef TFM_NO_STDLIB #include #include #include #include -#include +#else +#include +#include +#endif /* 0xMaMiPaDe * Major @@ -251,16 +266,22 @@ #endif #endif -/* use arc4random on platforms that support it */ -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) - #define FP_GEN_RANDOM() arc4random() - #define FP_GEN_RANDOM_MAX 0xffffffff -#endif +#ifdef FP_GEN_RANDOM + #ifndef FP_GEN_RANDOM_MAX + #error FP_GEN_RANDOM_MAX must be defined with FP_GEN_RANDOM + #endif +#elif !defined(TFM_NO_STDLIB) + /* use arc4random on platforms that support it */ + #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) + #define FP_GEN_RANDOM() arc4random() + #define FP_GEN_RANDOM_MAX 0xffffffff + #endif -/* use rand() as fall-back if there's no better rand function */ -#ifndef FP_GEN_RANDOM - #define FP_GEN_RANDOM() rand() - #define FP_GEN_RANDOM_MAX RAND_MAX + /* use rand() as fall-back if there's no better rand function */ + #ifndef FP_GEN_RANDOM + #define FP_GEN_RANDOM() rand() + #define FP_GEN_RANDOM_MAX RAND_MAX + #endif #endif /* some default configurations. @@ -340,11 +361,17 @@ const char *fp_ident(void); /* set to a small digit */ void fp_set(fp_int *a, fp_digit b); +#ifdef FP_GEN_RANDOM /* makes a pseudo-random int of a given size */ void fp_rand(fp_int *a, int digits); +#endif /* copy from a to b */ -#define fp_copy(a, b) (void)(((a) != (b)) && memcpy((b), (a), sizeof(fp_int))) +#define fp_copy(a, b) do { \ + void *_a = (a); \ + void *_b = (b); \ + if (_a != _b) memcpy(_b, _a, sizeof(fp_int)); \ +} while (0) #define fp_init_copy(a, b) fp_copy(b, a) /* clamp digits */ diff --git a/src/headers/tfm_private.h b/src/headers/tfm_private.h index 5c41d5c..c6dea2f 100644 --- a/src/headers/tfm_private.h +++ b/src/headers/tfm_private.h @@ -19,6 +19,50 @@ #endif /* VARIOUS LOW LEVEL STUFFS */ +#ifdef TFM_NO_STDLIB +FP_PRIVATE void fp_memcpy(void *restrict dst, const void *restrict src, size_t n); +FP_PRIVATE void fp_memset(void *restrict dst, unsigned char c, size_t n); + +#define toupper(C) __extension__({ \ + int _c = (int)(C); \ + 'a' <= _c && 'z' >= _c ? _c - ((int)'a' - (int)'A') : _c; \ +}) + +#define memcpy(D, S, N) __extension__({ \ + uint8_t *_dst = (uint8_t*)(D); \ + const uint8_t *_src = (uint8_t*)(S); \ + size_t _n = (size_t)(N); \ + if (__builtin_constant_p(_n)) { \ + for (size_t _i = 0; _i < _n; ++_i) _dst[_i] = _src[_i]; \ + } else { \ + fp_memcpy(_dst, _src, _n); \ + } \ + (void *)_dst; \ +}) + +/* The loop increment of 128 bytes was determined experimentally - it results + * in good inline code optimizations in both GCC and clang. */ +#define memset(D, C, N) __extension__({ \ + uint8_t *_dst = (uint8_t*)(D); \ + uint8_t _c = (uint8_t)(C); \ + size_t _n = (size_t)(N); \ + if (__builtin_constant_p(_n)) { \ + size_t _b = _n >> 7, _r = _n & 127; \ + for (size_t _i = 0; _i < _b; ++_i) { \ + size_t _j = 0; \ + for (;_j < 64; ++_j) *_dst++ = 0; \ + for (;_j < 128; ++_j) *_dst++ = 0; \ + } \ + size_t _i = 0; \ + if (_r > 0) for (;_i < 64 && _i < _r; ++_i) *_dst++ = _c; \ + if (_r > 64) for (;_i < 128 && _i < _r; ++_i) *_dst++ = _c; \ + } else { \ + fp_memset(_dst, _c, _n); \ + } \ + (void *)_dst; \ +}) +#endif + FP_PRIVATE void s_fp_add(fp_int *a, fp_int *b, fp_int *c); FP_PRIVATE void s_fp_sub(fp_int *a, fp_int *b, fp_int *c); FP_PRIVATE void fp_reverse(unsigned char *s, int len); diff --git a/src/misc/fp_ident.c b/src/misc/fp_ident.c index 5ab533f..2f42df2 100644 --- a/src/misc/fp_ident.c +++ b/src/misc/fp_ident.c @@ -6,23 +6,65 @@ #define GIT_VERSION TFM_VERSION_S #endif +#define dnstrcon(D, N, S) dnmemcpy((D), (N), S, sizeof(S)-1) +static signed long dnmemcpy(char **d, size_t *n, const char *s, size_t len) { + if (len >= *n) return -1; + memcpy(*d, s, len); + *n -= len; + *d += len; + **d = '\0'; + return len; +} + +/* log(2)/log(10) ~= 0.30102999... ~= 30103 / 100000 + * we need to add one byte because this rounds to zero, and one for sign + * these provide exact answer for integers up to 4720 bytes wide... */ +#define U_DIGITS(T) (1 + ((sizeof(T) * 8UL) * 30103UL) / 100000UL) +#define S_DIGITS(T) (2 + ((sizeof(T) * 8UL - 1) * 30103UL) / 100000UL) + +static signed long dnstrul(char **d, size_t *n, unsigned long value) { + char digits[U_DIGITS(unsigned long)+1]; /* fit digits plus null byte */ + char *digit = digits + (sizeof(digits) - 1); + size_t len = 0; + *digit = '\0'; + do { + *--digit = '0' + (value % 10); + value /= 10; + ++len; + if (digit < digits) return -1; + } while (value); + if (len >= *n) return -1; + return dnmemcpy(d, n, digit, len); +} + const char *fp_ident(void) { static char buf[1024]; + char *d = buf; + size_t n = sizeof(buf); - memset(buf, 0, sizeof(buf)); - snprintf(buf, sizeof(buf)-1, + dnstrcon(&d, &n, "TomsFastMath " GIT_VERSION "\n" #if defined(TFM_IDENT_BUILD_DATE) "Built on " __DATE__ " at " __TIME__ "\n" #endif "\n" "Sizeofs\n" -"\tfp_digit = %lu\n" -"\tfp_word = %lu\n" -"\n" -"FP_MAX_SIZE = %u\n" +"\tfp_digit = " + ); + dnstrul(&d, &n, sizeof(fp_digit)); + dnstrcon(&d, &n, "\n" +"\tfp_word = " + ); + dnstrul(&d, &n, sizeof(fp_word)); + dnstrcon(&d, &n, +"\n\n" +"FP_MAX_SIZE = " + ); + dnstrul(&d, &n, FP_MAX_SIZE); + dnstrcon(&d, &n, +"\n\n" "Defines: \n" #ifdef __i386__ " __i386__ " @@ -70,12 +112,17 @@ const char *fp_ident(void) #ifdef TFM_HUGE " TFM_HUGE " #endif -"\n", (unsigned long)sizeof(fp_digit), (unsigned long)sizeof(fp_word), FP_MAX_SIZE); +"\n" + ); if (sizeof(fp_digit) == sizeof(fp_word)) { - strncat(buf, "WARNING: sizeof(fp_digit) == sizeof(fp_word), this build is likely to not work properly.\n", - sizeof(buf) - strlen(buf) - 1); + dnstrcon(&d, &n, + "WARNING: sizeof(fp_digit) == sizeof(fp_word)," + " this build is likely to not work properly.\n" + ); } + + memset(d, 0, n); return buf; } diff --git a/src/misc/fp_memcpy.c b/src/misc/fp_memcpy.c new file mode 100644 index 0000000..9a2f7c3 --- /dev/null +++ b/src/misc/fp_memcpy.c @@ -0,0 +1,10 @@ +#include + +#ifdef TFM_NO_STDLIB +/* rely on compiler to provide optimized version */ +void fp_memcpy(void *restrict dst, const void *restrict src, size_t n) { + uint8_t *d = dst; + const uint8_t *s = src; + for (size_t i = 0; i < n; ++i) d[i] = s[i]; +} +#endif diff --git a/src/misc/fp_memset.c b/src/misc/fp_memset.c new file mode 100644 index 0000000..efa1e7b --- /dev/null +++ b/src/misc/fp_memset.c @@ -0,0 +1,9 @@ +#include + +#ifdef TFM_NO_STDLIB +/* rely on compiler to provide optimized version */ +void fp_memset(void *restrict dst, unsigned char c, size_t n) { + uint8_t *d = dst; + for (size_t i = 0; i < n; ++i) d[i] = c; +} +#endif diff --git a/src/misc/fp_rand.c b/src/misc/fp_rand.c index d5e8b81..f9b3744 100644 --- a/src/misc/fp_rand.c +++ b/src/misc/fp_rand.c @@ -2,6 +2,8 @@ /* SPDX-License-Identifier: Unlicense */ #include +#ifdef FP_GEN_RANDOM + #if FP_GEN_RANDOM_MAX == 0xffffffff #define FP_GEN_RANDOM_SHIFT 32 #elif FP_GEN_RANDOM_MAX == 32767 @@ -52,3 +54,4 @@ void fp_rand(fp_int *a, int digits) return; } +#endif diff --git a/src/numtheory/fp_prime_random_ex.c b/src/numtheory/fp_prime_random_ex.c index 58f5c3b..9227c56 100644 --- a/src/numtheory/fp_prime_random_ex.c +++ b/src/numtheory/fp_prime_random_ex.c @@ -5,8 +5,10 @@ /* This is possibly the mother of all prime generation functions, muahahahahaha! */ int fp_prime_random_ex(fp_int *a, int t, int size, int flags, tfm_prime_callback cb, void *dat) { - unsigned char *tmp, maskAND, maskOR_msb, maskOR_lsb; - int res, err, bsize, maskOR_msb_offset; + /* calc the byte size */ + unsigned char tmp[(size>>3)+(size&7?1:0)]; + unsigned char maskAND, maskOR_msb, maskOR_lsb; + int res, maskOR_msb_offset; /* sanity check the input */ if (size <= 1 || cb == NULL || t <= 0 || t > FP_PRIME_SIZE) { @@ -18,15 +20,6 @@ int fp_prime_random_ex(fp_int *a, int t, int size, int flags, tfm_prime_callback flags |= TFM_PRIME_BBS; } - /* calc the byte size */ - bsize = (size>>3)+(size&7?1:0); - - /* we need a buffer of bsize bytes */ - tmp = malloc(bsize); - if (tmp == NULL) { - return FP_MEM; - } - /* calc the maskAND value for the MSbyte*/ maskAND = 0xFF >> ((8 - (size & 7)) & 7); @@ -47,9 +40,8 @@ int fp_prime_random_ex(fp_int *a, int t, int size, int flags, tfm_prime_callback do { /* read the bytes */ - if (cb(tmp, bsize, dat) != bsize) { - err = FP_VAL; - goto error; + if (cb(tmp, sizeof(tmp), dat) != (int)sizeof(tmp)) { + return FP_VAL; } /* work over the MSbyte */ @@ -58,10 +50,10 @@ int fp_prime_random_ex(fp_int *a, int t, int size, int flags, tfm_prime_callback /* mix in the maskORs */ tmp[maskOR_msb_offset] |= maskOR_msb; - tmp[bsize-1] |= maskOR_lsb; + tmp[sizeof(tmp)-1] |= maskOR_lsb; /* read it in */ - fp_read_unsigned_bin(a, tmp, bsize); + fp_read_unsigned_bin(a, tmp, sizeof(tmp)); /* is it prime? */ res = fp_isprime_ex(a, t); @@ -83,8 +75,5 @@ int fp_prime_random_ex(fp_int *a, int t, int size, int flags, tfm_prime_callback fp_add_d(a, 1, a); } - err = FP_OKAY; -error: - free(tmp); - return err; + return FP_OKAY; }