/**
* This program uses the Hsieh SuperFastHash hash function as a PRNG
* by simulating the process of feeding it successively longer blocks
* of all zeros. Each 32-bit hash value doubles as the pseudo-random
* number which is written as binary on stdout in the byte order of
* the machine.
*
* The last time I ran this program and fed its output to dieharder,
* it had the following failures:
*
*
* FAILED ... RGB Bit Distribution Test
* FAILED ... RGB Generalized Minimum Distance Test
* FAILED ... RGB Lagged Sum Test
* FAILED ... RGB Permutations Test
* FAILED ... STS Monobit Test
* FAILED ... STS Runs Test
* FAILED ... STS Serial Test (Generalized)
* FAILED ... Diehard Count the 1s (stream) Test
* FAILED ... Diehard Craps Test
* FAILED ... Diehard OPSO
* FAILED ... Diehard OQSO Test
* FAILED ... Diehard Squeeze Test
* FAILED ... Lagged Sum Test
* FAILED ... Marsaglia and Tsang GCD Test
*
*
* The web page for the Hsieh SuperFastHash is as follows:
*
*
* http://www.azillionmonkeys.com/qed/hash.html
*
*
* @file
* @brief Hsieh SuperFastHash hash function as PRNG
*/
#include
#include
#include
#include
int
main(int argc,
char* argv[])
{
int rv = 0;
uint32_t a = 0xaa87231f;
uint32_t b = 0;
uint32_t tmp = 0;
uint32_t block_size = 0;
for (block_size = 0 ; ; ++block_size) {
#if 0
/* Check for overflow. */
if (block_size == UINT32_MAX) {
fprintf(stderr, "*** Error: block_size overflow detected.\n");
rv = 1;
break;
}
#endif
/* Special case for empty block. */
if (block_size == 0) {
b = 0;
goto bottom;
}
/* This is equivalent to the main loop. Remember the main loop
* works on 4 bytes at a time. Also, note that because the next
* byte is always zero, most of the calculation degenerates. */
if ((block_size >= 4) && ((block_size & 3) == 0)) {
tmp = 0 ^ a;
a = (a << 16) ^ tmp;
a += a >> 11;
}
/* Post-processing starts here. Again, because the bytes are all
* zero, most of the calculation degenerates. */
b = a;
switch (block_size & 3) {
case 3:
b ^= b << 16;
b += b >> 11;
break;
case 2:
b ^= b << 11;
b += b >> 17;
break;
case 1:
b ^= b << 10;
b += b >> 1;
break;
default:
break;
}
#if 0
/* If you look at what is currently "Update(5)" on the Hsieh
* SuperFastHash web page, it says not to bother with mixing
* the block size into the hash result when you want an
* "incremental version of the hash function". Without mixing
* the block size, 1 out of every 4 [!] blocks collide, and
* SuperFastHash fails a few more tests in dieharder.
*/
b ^= block_size;
#endif
/* Do the final mixing. */
b ^= b << 3;
b += b >> 5;
b ^= b << 4;
b += b >> 17;
b ^= b << 25;
b += b >> 6;
bottom:
/* Write the hash value to stdout as binary in the byte order
* of the machine. */
if (fwrite(&b, sizeof(b), 1, stdout) != 1) {
if (feof(stdout)) {
fprintf(stderr, "*** Error: fwrite: Unexpected EOF.\n");
} else {
fprintf(stderr, "*** Error: fwrite: %s\n", strerror(errno));
}
rv = 1;
break;
}
}
return rv;
}