#include #include #include #include "rng.h" #ifdef __APPLE__ #include #else #include #endif using namespace std; //adapted from http://blog.regehr.org/archives/1063 (rotl32c version) inline uint64_t rotl64(uint64_t x,uint32_t n){ assert(n<64); return (x<>(-n&63)); } inline uint64_t rotr64(uint64_t x,uint32_t n){ assert(n<64); return (x>>n)|(x<<(-n&63)); } KeyRng::KeyRng(const char *key_,int keylen_) :keylen(keylen_),idx(0),state(0){ if(keylen<=0)throw invalid_argument("KeyRng: Key should not be empty"); assert(key_); key=new uint8_t[keylen]; memcpy(key,key_,keylen); stir(); } KeyRng::KeyRng(const string &key_) :keylen(key_.size()),idx(0),state(0){ if(keylen==0)throw invalid_argument("KeyRng: Key should not be empty"); key=new uint8_t[keylen]; memcpy(key,key_.data(),keylen); stir(); } KeyRng::~KeyRng(){ delete[] key; } void KeyRng::stir(){ for(int i=0;i<10;i++)get(); } uint32_t KeyRng::get(){ //Progressively and cyclicly mixes in the key with the state. //Mostly own creation; the "tempering" part is derived from a (part of a) Mersenne Twister implementation. //In terms of distribution of values, this is similar to arc4random(). //This passes DieHarder 3.31.1 (tested 2016/10/06) with 2 "weak" results. The initial key "wachtwoord" was used. //At least n subsequent values should be independent, where n is the length of the initial key. state^=key[idx]; state+=17; key[idx]+=13; idx=(idx+1)%keylen; state^=rotr64(state,11); //tempering state^=rotl64(state,7)&0x9d2c5680; state^=rotr64(state,18); return state>>32; } uint32_t KeyRng::get_uniform(uint32_t upbound){ if(upbound<=1)return 0; uint32_t min=((uint64_t)1<<32)%upbound; //this is the amount of unusable RNG outputs when avoiding modulo bias while(true){ uint32_t v=get(); if(v>=min)return v%upbound; } } uint32_t CryptoRng::get(){ return arc4random(); } uint32_t CryptoRng::get_uniform(uint32_t upbound){ return arc4random_uniform(upbound); }