-
Marek Vavruša authored
previously cryptolib random function was used to generate message id, this works well but it is slow especially when the entropy is low, replaced with cryptographically safe prng ISAAC the ccan directory is going to be used in the future, as it's include structure makes it easy to embed C snippets instead of reimplementing them
Marek Vavruša authoredpreviously cryptolib random function was used to generate message id, this works well but it is slow especially when the entropy is low, replaced with cryptographically safe prng ISAAC the ccan directory is going to be used in the future, as it's include structure makes it easy to embed C snippets instead of reimplementing them
isaac.c 6.70 KiB
/*Written by Timothy B. Terriberry (tterribe@xiph.org) 1999-2009.
CC0 (Public domain) - see LICENSE file for details
Based on the public domain implementation by Robert J. Jenkins Jr.*/
#include <float.h>
#include <math.h>
#include <string.h>
#include <ccan/ilog/ilog.h>
#include "isaac.h"
#define ISAAC_MASK (0xFFFFFFFFU)
/* Extract ISAAC_SZ_LOG bits (starting at bit 2). */
static inline uint32_t lower_bits(uint32_t x)
{
return (x & ((ISAAC_SZ-1) << 2)) >> 2;
}
/* Extract next ISAAC_SZ_LOG bits (starting at bit ISAAC_SZ_LOG+2). */
static inline uint32_t upper_bits(uint32_t y)
{
return (y >> (ISAAC_SZ_LOG+2)) & (ISAAC_SZ-1);
}
static void isaac_update(isaac_ctx *_ctx){
uint32_t *m;
uint32_t *r;
uint32_t a;
uint32_t b;
uint32_t x;
uint32_t y;
int i;
m=_ctx->m;
r=_ctx->r;
a=_ctx->a;
b=_ctx->b+(++_ctx->c);
for(i=0;i<ISAAC_SZ/2;i++){
x=m[i];
a=(a^a<<13)+m[i+ISAAC_SZ/2];
m[i]=y=m[lower_bits(x)]+a+b;
r[i]=b=m[upper_bits(y)]+x;
x=m[++i];
a=(a^a>>6)+m[i+ISAAC_SZ/2];
m[i]=y=m[lower_bits(x)]+a+b;
r[i]=b=m[upper_bits(y)]+x;
x=m[++i];
a=(a^a<<2)+m[i+ISAAC_SZ/2];
m[i]=y=m[lower_bits(x)]+a+b;
r[i]=b=m[upper_bits(y)]+x;
x=m[++i];
a=(a^a>>16)+m[i+ISAAC_SZ/2];
m[i]=y=m[lower_bits(x)]+a+b;
r[i]=b=m[upper_bits(y)]+x;
}
for(i=ISAAC_SZ/2;i<ISAAC_SZ;i++){
x=m[i];
a=(a^a<<13)+m[i-ISAAC_SZ/2];
m[i]=y=m[lower_bits(x)]+a+b;
r[i]=b=m[upper_bits(y)]+x;
x=m[++i];
a=(a^a>>6)+m[i-ISAAC_SZ/2];
m[i]=y=m[lower_bits(x)]+a+b;
r[i]=b=m[upper_bits(y)]+x;
x=m[++i];
a=(a^a<<2)+m[i-ISAAC_SZ/2];
m[i]=y=m[lower_bits(x)]+a+b;
r[i]=b=m[upper_bits(y)]+x;
x=m[++i];
a=(a^a>>16)+m[i-ISAAC_SZ/2];
m[i]=y=m[lower_bits(x)]+a+b;
r[i]=b=m[upper_bits(y)]+x;
}
_ctx->b=b;
_ctx->a=a;
_ctx->n=ISAAC_SZ;
}
static void isaac_mix(uint32_t _x[8]){
static const unsigned char SHIFT[8]={11,2,8,16,10,4,8,9};
int i;
for(i=0;i<8;i++){
_x[i]^=_x[(i+1)&7]<<SHIFT[i];
_x[(i+3)&7]+=_x[i];
_x[(i+1)&7]+=_x[(i+2)&7];
i++;
_x[i]^=_x[(i+1)&7]>>SHIFT[i];
_x[(i+3)&7]+=_x[i];
_x[(i+1)&7]+=_x[(i+2)&7];
}
}
void isaac_init(isaac_ctx *_ctx,const unsigned char *_seed,int _nseed){
_ctx->a=_ctx->b=_ctx->c=0;
memset(_ctx->r,0,sizeof(_ctx->r));
isaac_reseed(_ctx,_seed,_nseed);
}
void isaac_reseed(isaac_ctx *_ctx,const unsigned char *_seed,int _nseed){
uint32_t *m;
uint32_t *r;
uint32_t x[8];
int i;
int j;
m=_ctx->m;
r=_ctx->r;
if(_nseed>ISAAC_SEED_SZ_MAX)_nseed=ISAAC_SEED_SZ_MAX;
for(i=0;i<_nseed>>2;i++){
r[i]^=(uint32_t)_seed[i<<2|3]<<24|(uint32_t)_seed[i<<2|2]<<16|
(uint32_t)_seed[i<<2|1]<<8|_seed[i<<2];
}
_nseed-=i<<2;
if(_nseed>0){
uint32_t ri;
ri=_seed[i<<2];
for(j=1;j<_nseed;j++)ri|=(uint32_t)_seed[i<<2|j]<<(j<<3);
r[i++]^=ri;
}
x[0]=x[1]=x[2]=x[3]=x[4]=x[5]=x[6]=x[7]=0x9E3779B9U;
for(i=0;i<4;i++)isaac_mix(x);
for(i=0;i<ISAAC_SZ;i+=8){
for(j=0;j<8;j++)x[j]+=r[i+j];
isaac_mix(x);
memcpy(m+i,x,sizeof(x));
}
for(i=0;i<ISAAC_SZ;i+=8){
for(j=0;j<8;j++)x[j]+=m[i+j];
isaac_mix(x);
memcpy(m+i,x,sizeof(x));
}
isaac_update(_ctx);
}
uint32_t isaac_next_uint32(isaac_ctx *_ctx){
if(!_ctx->n)isaac_update(_ctx);
return _ctx->r[--_ctx->n];
}
uint32_t isaac_next_uint(isaac_ctx *_ctx,uint32_t _n){
uint32_t r;
uint32_t v;
uint32_t d;
do{
r=isaac_next_uint32(_ctx);
v=r%_n;
d=r-v;
}
while(((d+_n-1)&ISAAC_MASK)<d);
return v;
}
/*Returns a uniform random float.
The expected value is within FLT_MIN (e.g., 1E-37) of 0.5.
_bits: An initial set of random bits.
_base: This should be -(the number of bits in _bits), up to -32.
Return: A float uniformly distributed between 0 (inclusive) and 1
(exclusive).
The average value was measured over 2**32 samples to be
0.50000037448772916.*/
static float isaac_float_bits(isaac_ctx *_ctx,uint32_t _bits,int _base){
float ret;
int nbits_needed;
while(!_bits){
if(_base+FLT_MANT_DIG<FLT_MIN_EXP)return 0;
_base-=32;
_bits=isaac_next_uint32(_ctx);
}
/*Note: This could also be determined with frexp(), for a slightly more
portable solution, but that takes twice as long, and one has to worry
about rounding effects, which can over-estimate the exponent when given
FLT_MANT_DIG+1 consecutive one bits.
Even the fallback C implementation of ILOGNZ_32() yields an implementation
25% faster than the frexp() method.*/
nbits_needed=FLT_MANT_DIG-ilog32_nz(_bits);
#if FLT_MANT_DIG>32
ret=ldexpf((float)_bits,_base);
# if FLT_MANT_DIG>65
while(32-nbits_needed<0){
# else
if(32-nbits_needed<0){
# endif
_base-=32;
nbits_needed-=32;
ret+=ldexpf((float)isaac_next_uint32(_ctx),_base);
}
_bits=isaac_next_uint32(_ctx)>>32-nbits_needed;
ret+=ldexpf((float)_bits,_base-nbits_needed);
#else
if(nbits_needed>0){
_bits=_bits<<nbits_needed|isaac_next_uint32(_ctx)>>(32-nbits_needed);
}
# if FLT_MANT_DIG<32
else _bits>>=-nbits_needed;
# endif
ret=ldexpf((float)_bits,_base-nbits_needed);
#endif
return ret;
}
float isaac_next_float(isaac_ctx *_ctx){
return isaac_float_bits(_ctx,0,0);
}
float isaac_next_signed_float(isaac_ctx *_ctx){
uint32_t bits;
bits=isaac_next_uint32(_ctx);
return (1|-((int)bits&1))*isaac_float_bits(_ctx,bits>>1,-31);
}
/*Returns a uniform random double.
_bits: An initial set of random bits.
_base: This should be -(the number of bits in _bits), up to -32.
Return: A double uniformly distributed between 0 (inclusive) and 1
(exclusive).
The average value was measured over 2**32 samples to be
0.500006289408060911*/
static double isaac_double_bits(isaac_ctx *_ctx,uint32_t _bits,int _base){
double ret;
int nbits_needed;
while(!_bits){
if(_base+DBL_MANT_DIG<DBL_MIN_EXP)return 0;
_base-=32;
_bits=isaac_next_uint32(_ctx);
}
nbits_needed=DBL_MANT_DIG-ilog32_nz(_bits);
#if DBL_MANT_DIG>32
ret=ldexp((double)_bits,_base);
# if DBL_MANT_DIG>65
while(32-nbits_needed<0){
# else
if(32-nbits_needed<0){
# endif
_base-=32;
nbits_needed-=32;
ret+=ldexp((double)isaac_next_uint32(_ctx),_base);
}
_bits=isaac_next_uint32(_ctx)>>(32-nbits_needed);
ret+=ldexp((double)_bits,_base-nbits_needed);
#else
if(nbits_needed>0){
_bits=_bits<<nbits_needed|isaac_next_uint32(_ctx)>>32-nbits_needed;
}
# if DBL_MANT_DIG<32
else _bits>>=-nbits_needed;
# endif
ret=ldexp((double)_bits,exp-DBL_MANT_DIG);
#endif
return ret;
}
double isaac_next_double(isaac_ctx *_ctx){
return isaac_double_bits(_ctx,0,0);
}
double isaac_next_signed_double(isaac_ctx *_ctx){
uint32_t bits;
bits=isaac_next_uint32(_ctx);
return (1|-((int)bits&1))*isaac_double_bits(_ctx,bits>>1,-31);
}