/** * 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; }