diff --git a/src/Rand.c b/src/Rand.c index cc304ee..fa48039 100644 --- a/src/Rand.c +++ b/src/Rand.c @@ -23,12 +23,80 @@ */ #include +#include #include #include #include #include +#define RAND_STATE_VECTOR_LENGTH 624 +#define RAND_STATE_VECTOR_M 397 + +#define RAND_UPPER_MASK 0x80000000 +#define RAND_LOWER_MASK 0x7FFFFFFF +#define RAND_TEMPER_B 0x9D2C5680 +#define RAND_TEMPER_C 0xEFC60000 + +typedef struct RandState +{ + UInt32 mt[RAND_STATE_VECTOR_LENGTH]; + int index; +} RandState; + +static void +RandSeed(RandState *state, UInt32 seed) +{ + state->mt[0] = seed & 0xFFFFFFFF; + + for (state->index = 1; state->index < RAND_STATE_VECTOR_LENGTH; state->index++) + { + state->mt[state->index] = (6069 * state->mt[state->index - 1]) & 0xFFFFFFFF; + } +} + +static UInt32 +RandGenerate(RandState *state) +{ + static const UInt32 mag[2] = { 0x0, 0x9908B0DF }; + + UInt32 result; + + if (state->index >= RAND_STATE_VECTOR_LENGTH || state->index < 0) + { + int kk; + + if (state->index >= RAND_STATE_VECTOR_LENGTH + 1 || state->index < 0) + { + RandSeed(state, 4357); + } + + for (kk = 0; kk < RAND_STATE_VECTOR_LENGTH - RAND_STATE_VECTOR_M; kk++) + { + result = (state->mt[kk] & RAND_UPPER_MASK) | (state->mt[kk + 1] & RAND_LOWER_MASK); + state->mt[kk] = state->mt[kk + RAND_STATE_VECTOR_M] ^ (result >> 1) ^ mag[result & 0x1]; + } + + for (; kk < RAND_STATE_VECTOR_LENGTH - 1; kk++) + { + result = (state->mt[kk] & RAND_UPPER_MASK) | (state->mt[kk + 1] & RAND_LOWER_MASK); + state->mt[kk] = state->mt[kk + (RAND_STATE_VECTOR_M - RAND_STATE_VECTOR_LENGTH)] ^ (result >> 1) ^ mag[result & 0x1]; + } + + result = (state->mt[RAND_STATE_VECTOR_LENGTH - 1] & RAND_UPPER_MASK) | (state->mt[0] & RAND_LOWER_MASK); + state->mt[RAND_STATE_VECTOR_LENGTH - 1] = state->mt[RAND_STATE_VECTOR_M - 1] ^ (result >> 1) ^ mag[result & 0x1]; + state->index = 0; + } + + result = state->mt[state->index++]; + result ^= (result >> 11); + result ^= (result << 7) & RAND_TEMPER_B; + result ^= (result << 15) & RAND_TEMPER_C; + result ^= (result >> 18); + + return result; +} + /* Generate random numbers using rejection sampling. The basic idea is * to "reroll" if a number happens to be outside the range. However * this could be extremely inefficient. @@ -44,20 +112,23 @@ void RandIntN(int *buf, size_t size, unsigned int max) { - static pthread_mutex_t seedLock = PTHREAD_MUTEX_INITIALIZER; - static unsigned int seed = 0; - int tmp; + static pthread_mutex_t stateLock = PTHREAD_MUTEX_INITIALIZER; + static UInt32 seed = 0; + static RandState state; /* Limit the range to banish all previously biased results */ const int allowed = RAND_MAX - RAND_MAX % max; + int tmp; size_t i; - pthread_mutex_lock(&seedLock); + pthread_mutex_lock(&stateLock); + if (!seed) { /* Generate a seed from the system time, PID, and TID */ seed = UtilServerTs() ^ getpid() ^ (unsigned long) pthread_self(); + RandSeed(&state, seed); } /* Generate {size} random numbers. */ @@ -66,13 +137,13 @@ RandIntN(int *buf, size_t size, unsigned int max) /* Most of the time, this will take about 1 loop */ do { - tmp = rand_r(&seed); - } while (tmp >= allowed); - /* Since a generated number here is never in the biased range, - * we can now safely use modulo. */ + tmp = RandGenerate(&state); + } while (tmp > allowed); + buf[i] = tmp % max; } - pthread_mutex_unlock(&seedLock); + + pthread_mutex_unlock(&stateLock); } /* Generate just 1 random number */ diff --git a/src/Sha2.c b/src/Sha2.c index 75295f4..9cea8d3 100644 --- a/src/Sha2.c +++ b/src/Sha2.c @@ -23,41 +23,18 @@ */ #include #include +#include #include #include #include -/* - * POSIX says that LONG_BIT and WORD_BIT are defined, but some notable - * non-conforming systems and compilers don't don't define it, or only - * define it in circumstances I'm unwilling to comply with (such as - * defining _GNU_SOURCE. - * - * So, unfortunately, although LONG_BIT and WORD_BIT are the most - * elegant solutions, we're forced to do this so we can check LONG_MAX - * and INT_MAX. - */ -#define BIT64_MAX 9223372036854775807 -#define BIT32_MAX 2147483647 -#define BIT16_MAX 32767 - -#if (defined(LONG_BIT) && LONG_BIT == 32) || (defined(LONG_MAX) && LONG_MAX == BIT32_MAX) -typedef unsigned long uint32_t; - -#elif (defined(WORD_BIT) && WORD_BIT == 32) || (defined(INT_MAX) && INT_MAX == BIT32_MAX) -typedef unsigned int uint32_t; - -#else -#error Unable to find suitable integer type for uint32_t -#endif - #define GET_UINT32(x) \ - (((uint32_t)(x)[0] << 24) | \ - ((uint32_t)(x)[1] << 16) | \ - ((uint32_t)(x)[2] << 8) | \ - ((uint32_t)(x)[3])) + (((UInt32)(x)[0] << 24) | \ + ((UInt32)(x)[1] << 16) | \ + ((UInt32)(x)[2] << 8) | \ + ((UInt32)(x)[3])) #define PUT_UINT32(dst, x) { \ (dst)[0] = (x) >> 24; \ @@ -79,8 +56,8 @@ typedef unsigned int uint32_t; #define WW(i) (w[i] = w[i - 16] + S0(w[i - 15]) + w[i - 7] + S1(w[i - 2])) #define ROUND(a, b, c, d, e, f, g, h, k, w) { \ - uint32_t tmp0 = h + T0(e) + CH(e, f, g) + k + w; \ - uint32_t tmp1 = T1(a) + MAJ(a, b, c); \ + UInt32 tmp0 = h + T0(e) + CH(e, f, g) + k + w; \ + UInt32 tmp1 = T1(a) + MAJ(a, b, c); \ h = tmp0 + tmp1; \ d += tmp0; \ } @@ -88,7 +65,7 @@ typedef unsigned int uint32_t; typedef struct Sha256Context { size_t length; - uint32_t state[8]; + UInt32 state[8]; size_t bufLen; unsigned char buffer[64]; } Sha256Context; @@ -96,7 +73,7 @@ typedef struct Sha256Context static void Sha256Chunk(Sha256Context * context, unsigned char chunk[64]) { - const uint32_t rk[64] = { + const UInt32 rk[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, @@ -110,8 +87,8 @@ Sha256Chunk(Sha256Context * context, unsigned char chunk[64]) 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; - uint32_t w[64]; - uint32_t a, b, c, d, e, f, g, h; + UInt32 w[64]; + UInt32 a, b, c, d, e, f, g, h; int i; @@ -202,10 +179,10 @@ Sha256(char *str) char *outStr; unsigned char fill[64]; - uint32_t fillLen; + UInt32 fillLen; unsigned char buf[8]; - uint32_t hiLen; - uint32_t loLen; + UInt32 hiLen; + UInt32 loLen; if (!str) { @@ -237,8 +214,8 @@ Sha256(char *str) fill[0] = 0x80; fillLen = (context.bufLen < 56) ? 56 - context.bufLen : 120 - context.bufLen; - hiLen = (uint32_t) (context.length >> 29); - loLen = (uint32_t) (context.length << 3); + hiLen = (UInt32) (context.length >> 29); + loLen = (UInt32) (context.length << 3); PUT_UINT32(&buf[0], hiLen); PUT_UINT32(&buf[4], loLen); diff --git a/src/include/Int.h b/src/include/Int.h new file mode 100644 index 0000000..552cf33 --- /dev/null +++ b/src/include/Int.h @@ -0,0 +1,73 @@ +#ifndef TELODENDRIA_INT_H +#define TELODENDRIA_INT_H + +#include + +#define BIT64_MAX 18446744073709551615 +#define BIT32_MAX 4294967295 +#define BIT16_MAX 65535 +#define BIT8_MAX 255 + +#ifndef UCHAR_MAX +#error Size of char data type is unknown. Define UCHAR_MAX. +#endif + +#ifndef USHRT_MAX +#error Size of short data type is unknown. Define USHRT_MAX. +#endif + +#ifndef UINT_MAX +#error Size of int data type is unknown. Define UINT_MAX. +#endif + +#ifndef ULONG_MAX +#error Size of long data type is unknown. Define ULONG_MAX. +#endif + +#if UCHAR_MAX == BIT8_MAX +typedef signed char Int8; +typedef unsigned char UInt8; + +#else +#error Unable to determine suitable data type for 8-bit integers. +#endif + +#if UINT_MAX == BIT16_MAX +typedef signed int Int16; +typedef unsigned int UInt16; + +#elif USHRT_MAX == BIT16_MAX +typedef signed short Int16; +typedef unsigned short UInt16; + +#elif UCHAR_MAX == BIT16_MAX +typedef signed char Int16; +typedef unsigned char UInt16; + +#else +#error Unable to determine suitable data type for 16-bit integers. +#endif + +#if ULONG_MAX == BIT32_MAX +typedef signed long Int32; +typedef unsigned long UInt32; + +#elif UINT_MAX == BIT32_MAX +typedef signed int Int32; +typedef unsigned int UInt32; + +#elif USHRT_MAX == BIT32_MAX +typedef signed short Int32; +typedef unsigned short UInt32; + +#elif UCHAR_MAX == BIT32_MAX +typedef signed char Int32; +typedef unsigned char UInt32; + +#else +#error Unable to determine suitable data type for 32-bit integers. +#endif + +/* The ANSI C standard only guarantees a data size of up to 32 bits. */ + +#endif diff --git a/tools/bin/td b/tools/bin/td index 4fde88d..29fc85f 100644 --- a/tools/bin/td +++ b/tools/bin/td @@ -154,6 +154,10 @@ recipe_build() { fi fi done + + if ! intcheck; then + exit 1 + fi } recipe_run() { diff --git a/tools/src/intcheck.c b/tools/src/intcheck.c new file mode 100644 index 0000000..8dc1354 --- /dev/null +++ b/tools/src/intcheck.c @@ -0,0 +1,25 @@ +#include + +#include + +#define ASSERT_SIZE(type, size) \ + if ((sizeof(type) * 8) != size) \ + { \ + fputs(#type " is not " #size " bits.\n", stderr); \ + return 1; \ + } + +int +main(void) +{ + ASSERT_SIZE(Int8, 8); + ASSERT_SIZE(UInt8, 8); + + ASSERT_SIZE(Int16, 16); + ASSERT_SIZE(UInt16, 16); + + ASSERT_SIZE(Int32, 32); + ASSERT_SIZE(UInt32, 32); + + return 0; +}