I finished an output stream-based pseudorandom number generator, that works based on the current time and output data.
Here is the header's code (entrostream.hpp):
#ifndef ENTROSTREAM_HPP
#define ENTROSTREAM_HPP
#include <iostream>
#include <cstdlib>
#include <climits>
#include <sys/time.h>
#include <queue>
#include <sstream>
template <typename D> D rot_l(D x,unsigned r) { return ((x << r) | (x >> (CHAR_BIT*sizeof(D)-r))); }
template <typename D> D rot_r(D x,unsigned r) { return ((x >> r) | (x << (CHAR_BIT*sizeof(D)-r))); }
class entrostream : public std::ostream
{
private:
unsigned transform(unsigned x) // A "hashing/pseudorandom" function
{
unsigned yi[8] = {
0xAD3012F1,0x56E7BA0E,0x2CD091FF,0x1FF5D329,
0x435A0FF2,0x912ACD1A,0xB0AFE143,0x33FF0A10
};
unsigned y[8];
unsigned yf = 0xC0FDE3A0;
for (int i=0;i<8;i++)
{
unsigned t1 = (rot_l(x/(i+1),8-i) >> 2*i) & 0xFF;
unsigned t2 = (rot_r(x/(i+1),8-i) >> 2*i) & 0xFF;
y[i] = ((t1 << 16) | t2)^yi[i];
}
for (int i=0;i<8;i++)
{
for (int j=0;j<8;j++)
{
y[j] = rot_r(y[i],yi[j]&0x1F)^y[j]^x;
}
yi[i] = rot_l(yi[i],4*i)^y[i];
}
for (int i=0;i<8;i++)
{
unsigned t = 0x1043F03A;
for (int j=0;j<8;j++)
{
t ^= rot_l(y[i]^yi[j],(i+4*j)%32);
}
yf ^= rot_r(t,4*i);
}
return yf;
}
unsigned tv_hash(struct timeval x) { return (unsigned(x.tv_sec) << 16) | unsigned(x.tv_usec); }
unsigned str_to_u(char in,int idx) { return (unsigned(in) << 4*idx); }
std::queue<unsigned> buffer;
std::ostringstream data;
public:
entrostream(int _argc,char **_argv) // Generate randomness from arguments
{
struct timeval ts;
std::string tmp[_argc];
for (int i=0;i<_argc;i++) { tmp[i] = _argv[i]; }
for (int i=0;i<_argc;i++)
{
for (int j=0;j<tmp[i].length()/4;j+=4)
{
gettimeofday(&ts,NULL);
unsigned th = tv_hash(ts);
unsigned uis = str_to_u(tmp[i][j],i%4) |
str_to_u(tmp[i][j+1],(j+1)%4) |
str_to_u(tmp[i][j+2],(j+2)%4) |
str_to_u(tmp[i][j+3],(j+3)%4);
unsigned ui = transform(uis)^transform(th);
buffer.push(ui);
}
}
}
entrostream()
{
struct timeval ts;
gettimeofday(&ts,NULL);
unsigned th = transform(tv_hash(ts));
buffer.push(th);
}
template <typename T> entrostream& operator<<(const T& val) // Generate more randomness from output stuff
{
struct timeval ts;
std::cout << val;
data << val;
std::string tmp = data.str();
for (int i=0;i<tmp.length()/4;i+=4)
{
gettimeofday(&ts,NULL);
unsigned th = tv_hash(ts);
unsigned uis = str_to_u(tmp[i],i%4) |
str_to_u(tmp[i+1],(i+1)%4) |
str_to_u(tmp[i+2],(i+2)%4) |
str_to_u(tmp[i+3],(i+3)%4);
unsigned ui = transform(uis)^transform(th);
buffer.push(ui);
}
return *this;
}
unsigned operator()() // Get a number and generate another one
{
unsigned o;
struct timeval ts;
gettimeofday(&ts,NULL);
buffer.push(transform(tv_hash(ts)));
if (!buffer.empty())
{
o = buffer.front();
buffer.pop();
}
else
o = 0;
return o;
}
};
#endif
Here is an example of its usage:
#include <iostream>
#include <cstdlib>
#include "entrostream.hpp"
using namespace std;
int main(int argc,char **argv)
{
entrostream eout(argc,argv);
eout << "Hello.\n";
unsigned x = eout();
eout << "entrostream output 1: " << x << "\n";
x = eout();
eout << "entrostream output 2: " << x << "\n";
x = eout();
eout << "entrostream output 3: " << x << "\n";
x = eout();
eout << "entrostream output 4: " << x << "\n";
x = eout();
cout << "entrostream output 5: " << x << "\n";
}
As always, suggestions, improvements, etc. are welcome.