Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow tomsfastmath to be built without stdlib #34

Draft
wants to merge 3 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
49 changes: 38 additions & 11 deletions src/headers/tfm.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,26 @@
#ifndef TFM_H_
#define TFM_H_

#if TFM_NO_STDLIB
/* do nothing */
Comment on lines +12 to +13
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This worries me a bit, 'cause it allows anyone to defined -DTOM_NO_STDLIB=1 regardless of compiler, and when looking through the code, this feature makes heavy use of GCC features.

People might want to build without having to link with stdlib for other reasons than webasm...

It's possible that this should simply be documented with fierce warnings not to try this with other compilers than GCC or derivatives thereof (like clang)

#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 <limits.h>
#ifndef TFM_NO_STDLIB
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
#else
#include <stddef.h>
#include <stdint.h>
#endif

/* 0xMaMiPaDe
* Major
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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 */
Expand Down
44 changes: 44 additions & 0 deletions src/headers/tfm_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
65 changes: 56 additions & 9 deletions src/misc/fp_ident.c
Original file line number Diff line number Diff line change
Expand Up @@ -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__ "
Expand Down Expand Up @@ -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;
}

Expand Down
10 changes: 10 additions & 0 deletions src/misc/fp_memcpy.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include <tfm_private.h>

#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
9 changes: 9 additions & 0 deletions src/misc/fp_memset.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include <tfm_private.h>

#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
3 changes: 3 additions & 0 deletions src/misc/fp_rand.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
/* SPDX-License-Identifier: Unlicense */
#include <tfm_private.h>

#ifdef FP_GEN_RANDOM

#if FP_GEN_RANDOM_MAX == 0xffffffff
#define FP_GEN_RANDOM_SHIFT 32
#elif FP_GEN_RANDOM_MAX == 32767
Expand Down Expand Up @@ -52,3 +54,4 @@ void fp_rand(fp_int *a, int digits)
return;

}
#endif
29 changes: 9 additions & 20 deletions src/numtheory/fp_prime_random_ex.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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);

Expand All @@ -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 */
Expand All @@ -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);
Expand All @@ -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;
}