Aer/engine/lib/random.c
belliash 2d99881240
All checks were successful
The build was successful.
Get rid of manual optimisation technique.
This optimisation technique results in non insignificant speed boost on some old x86 architectures. Novadays, we should rely on compiler optimisation.
2018-08-21 06:27:07 +02:00

129 lines
3.3 KiB
C

#include "ph7int.h"
/*
* Psuedo Random Number Generator (PRNG)
* @authors: SQLite authors <http://www.sqlite.org/>
* @status: Public Domain
* NOTE:
* Nothing in this file or anywhere else in the library does any kind of
* encryption.The RC4 algorithm is being used as a PRNG (pseudo-random
* number generator) not as an encryption device.
*/
#define SXPRNG_MAGIC 0x13C4
#ifdef __UNIXES__
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#endif
static sxi32 SyOSUtilRandomSeed(void *pBuf, sxu32 nLen, void *pUnused) {
char *zBuf = (char *)pBuf;
#ifdef __WINNT__
DWORD nProcessID; /* Yes,keep it uninitialized when compiling using the MinGW32 builds tools */
#elif defined(__UNIXES__)
pid_t pid;
int fd;
#else
char zGarbage[128]; /* Yes,keep this buffer uninitialized */
#endif
SXUNUSED(pUnused);
#ifdef __WINNT__
#ifndef __MINGW32__
nProcessID = GetProcessId(GetCurrentProcess());
#endif
SyMemcpy((const void *)&nProcessID, zBuf, SXMIN(nLen, sizeof(DWORD)));
if((sxu32)(&zBuf[nLen] - &zBuf[sizeof(DWORD)]) >= sizeof(SYSTEMTIME)) {
GetSystemTime((LPSYSTEMTIME)&zBuf[sizeof(DWORD)]);
}
#elif defined(__UNIXES__)
fd = open("/dev/urandom", O_RDONLY);
if(fd >= 0) {
if(read(fd, zBuf, nLen) > 0) {
close(fd);
return SXRET_OK;
}
/* FALL THRU */
}
close(fd);
pid = getpid();
SyMemcpy((const void *)&pid, zBuf, SXMIN(nLen, sizeof(pid_t)));
if(&zBuf[nLen] - &zBuf[sizeof(pid_t)] >= (int)sizeof(struct timeval)) {
gettimeofday((struct timeval *)&zBuf[sizeof(pid_t)], 0);
}
#else
/* Fill with uninitialized data */
SyMemcpy(zGarbage, zBuf, SXMIN(nLen, sizeof(zGarbage)));
#endif
return SXRET_OK;
}
PH7_PRIVATE sxi32 SyRandomnessInit(SyPRNGCtx *pCtx, ProcRandomSeed xSeed, void *pUserData) {
char zSeed[256];
sxu8 t;
sxi32 rc;
sxu32 i;
if(pCtx->nMagic == SXPRNG_MAGIC) {
return SXRET_OK; /* Already initialized */
}
/* Initialize the state of the random number generator once,
** the first time this routine is called.The seed value does
** not need to contain a lot of randomness since we are not
** trying to do secure encryption or anything like that...
*/
if(xSeed == 0) {
xSeed = SyOSUtilRandomSeed;
}
rc = xSeed(zSeed, sizeof(zSeed), pUserData);
if(rc != SXRET_OK) {
return rc;
}
pCtx->i = pCtx->j = 0;
for(i = 0; i < SX_ARRAYSIZE(pCtx->s) ; i++) {
pCtx->s[i] = (unsigned char)i;
}
for(i = 0; i < sizeof(zSeed) ; i++) {
pCtx->j += pCtx->s[i] + zSeed[i];
t = pCtx->s[pCtx->j];
pCtx->s[pCtx->j] = pCtx->s[i];
pCtx->s[i] = t;
}
pCtx->nMagic = SXPRNG_MAGIC;
return SXRET_OK;
}
/*
* Get a single 8-bit random value using the RC4 PRNG.
*/
static sxu8 randomByte(SyPRNGCtx *pCtx) {
sxu8 t;
/* Generate and return single random byte */
pCtx->i++;
t = pCtx->s[pCtx->i];
pCtx->j += t;
pCtx->s[pCtx->i] = pCtx->s[pCtx->j];
pCtx->s[pCtx->j] = t;
t += pCtx->s[pCtx->i];
return pCtx->s[t];
}
PH7_PRIVATE sxi32 SyRandomness(SyPRNGCtx *pCtx, void *pBuf, sxu32 nLen) {
unsigned char *zBuf = (unsigned char *)pBuf;
unsigned char *zEnd = &zBuf[nLen];
#if defined(UNTRUST)
if(pCtx == 0 || pBuf == 0 || nLen <= 0) {
return SXERR_EMPTY;
}
#endif
if(pCtx->nMagic != SXPRNG_MAGIC) {
return SXERR_CORRUPT;
}
for(;;) {
if(zBuf >= zEnd) {
break;
}
zBuf[0] = randomByte(pCtx);
zBuf++;
}
return SXRET_OK;
}