#include <algorithm>
#include <array>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <memory>
using namespace std;
class RBG;
class SimpleRBG;
class SHA1;
class BitInputStream;
template <class X> class PrimitiveBitInputStream;
class RBG {
public:
virtual bool getBit() = 0;
};
class SimpleRBG : public RBG {
public:
SimpleRBG();
virtual bool getBit();
protected:
shared_ptr<array<unsigned long, 5> > hash;
unsigned int pos;
};
class SHA1 {
public:
static shared_ptr<array<unsigned long, 5> > computeHash(const shared_ptr<BitInputStream>& msg);
protected:
SHA1();
typedef unsigned long (*FUNCTION)(const unsigned long& x, const unsigned long& y, const unsigned long& z);
static const FUNCTION FUNCTIONS[4];
static const unsigned long K[4];
static const unsigned long INITIAL_HASH_VALUES[5];
static unsigned long ch(const unsigned long& x, const unsigned long& y, const unsigned long& z);
static unsigned long parity(const unsigned long& x, const unsigned long& y, const unsigned long& z);
static unsigned long maj(const unsigned long& x, const unsigned long& y, const unsigned long& z);
};
class BitInputStream {
public:
virtual bool getBit() = 0;
virtual bool isEOF() = 0;
};
template <class X>
class PrimitiveBitInputStream : public BitInputStream {
public:
PrimitiveBitInputStream(const X& x);
virtual bool getBit();
virtual bool isEOF();
protected:
X x;
unsigned int pos;
PrimitiveBitInputStream(const PrimitiveBitInputStream& sbin);
PrimitiveBitInputStream& operator =(const PrimitiveBitInputStream& sbin);
};
template <class X> X rotateLeft(const X& x, const unsigned int& n, const unsigned int& w = (sizeof(X) << 3));
SimpleRBG::SimpleRBG() : hash(nullptr), pos(160) {
srand((unsigned int)time(nullptr) ^ (unsigned int)clock());
}
bool SimpleRBG::getBit() {
if (this->pos >= 160) {
this->hash = SHA1::computeHash(shared_ptr<BitInputStream>(new PrimitiveBitInputStream<int>(rand())));
this->pos = 0;
}
bool res = ((this->hash->at(this->pos >> 5) >> (32 - 1 - (this->pos & 0x1F))) & 1) == 1;
this->pos++;
return res;
}
const SHA1::FUNCTION SHA1::FUNCTIONS[4] = {
ch,
parity,
maj,
parity,
};
const unsigned long SHA1::K[4] = {
0x5a827999,
0x6ed9eba1,
0x8f1bbcdc,
0xca62c1d6,
};
const unsigned long SHA1::INITIAL_HASH_VALUES[5] = {
0x67452301,
0xefcdab89,
0x98badcfe,
0x10325476,
0xc3d2e1f0,
};
shared_ptr<array<unsigned long, 5> > SHA1::computeHash(const shared_ptr<BitInputStream>& msg) {
shared_ptr<array<unsigned long, 5> > hash(new array<unsigned long, 5>);
copy(INITIAL_HASH_VALUES, INITIAL_HASH_VALUES + 5, &hash->front());
shared_ptr<array<unsigned long, 16> > block(new array<unsigned long, 16>);
shared_ptr<array<unsigned long, 80> > sche(new array<unsigned long, 80>);
unsigned long long len = 0;
bool put_end = false;
bool put_len = false;
while (!put_len) {
block->fill(0);
unsigned int block_pos = 0;
for (; block_pos < 512 && !msg->isEOF(); block_pos++) {
block->at(block_pos >> 5) |= (msg->getBit() == true ? 1 : 0) << (32 - 1 - (block_pos & 0x1f));
len++;
}
if (block_pos < 512) {
if (!put_end) {
block->at(block_pos >> 5) |= 1 << (32 - 1 - (block_pos & 0x1f));
block_pos++;
put_end = true;
}
if (block_pos + 64 <= 512) {
block->at(14) = len >> 32;
block->at(15) = len & 0xffffffff;
put_len = true;
}
}
for (unsigned int i = 0; i < 80; i++) {
if (i < 16) sche->at(i) = block->at(i);
else sche->at(i) = rotateLeft(
sche->at(i - 3) ^
sche->at(i - 8) ^
sche->at(i - 14) ^
sche->at(i - 16), 1);
}
unsigned long a = hash->at(0);
unsigned long b = hash->at(1);
unsigned long c = hash->at(2);
unsigned long d = hash->at(3);
unsigned long e = hash->at(4);
for (unsigned int i = 0; i < 80; i++) {
unsigned long t =
rotateLeft(a, 5) +
FUNCTIONS[i / 20](b, c, d) +
e +
K[i / 20] +
sche->at(i);
e = d;
d = c;
c = rotateLeft(b, 30);
b = a;
a = t;
}
hash->at(0) += a;
hash->at(1) += b;
hash->at(2) += c;
hash->at(3) += d;
hash->at(4) += e;
}
return hash;
}
unsigned long SHA1::ch(const unsigned long& x, const unsigned long& y, const unsigned long& z) {
return (x & y) ^ (~x & z);
}
unsigned long SHA1::parity(const unsigned long& x, const unsigned long& y, const unsigned long& z) {
return x ^ y ^ z;
}
unsigned long SHA1::maj(const unsigned long& x, const unsigned long& y, const unsigned long& z) {
return (x & y) ^ (x & z) ^ (y & z);
}
template <class X>
PrimitiveBitInputStream<X>::PrimitiveBitInputStream(const X& x) : x(x), pos(0) {}
template <class X>
bool PrimitiveBitInputStream<X>::getBit() {
bool res = ((this->x >> ((sizeof(X) << 3) - 1 - this->pos)) & 1) == 1;
this->pos++;
return res;
}
template <class X>
bool PrimitiveBitInputStream<X>::isEOF() {
return this->pos >= (sizeof(X) << 3);
}
template <class X> X rotateLeft(const X& x, const unsigned int& n, const unsigned int& w) {
return (x << n) | (x >> (w - n));
}
int main() {
shared_ptr<RBG> rbg(new SimpleRBG());
for (unsigned int i = 0; i < 20; i++) {
for (unsigned int j = 0; j < 40; j++) {
cout << (rbg->getBit() == true ? '.' : ' ');
}
cout << endl;
}
return 0;
}