Boost logo

Boost :

From: Mark Borgerding (mborgerding_at_[hidden])
Date: 2000-02-24 11:02:32


I did some more work on the entropy pool/ clock() timing rng.

I had about 3MB of data from the clock() method. I put it through a
entropy-pool churning process described in my earlier email. I used a
32 bit CRC to churn the pool.

For those that are just tuning in, the idea was to get a value from
clock(), count in a tight loop until clock() changes, and use the lsb
of the count as a random bit. Eight bits of entropy are gathered this
way and then mixed into an entropy pool via a CRC. A byte of the
entropy pool is then used as a true random byte.

The following is a program that writes random bytes to stdout.

I analyzed the results with diehard and they looked really good.
Granted, I could not run all the tests, because some of them require >
10MB of data.
The abbreviated diehard results are after the program listing. Note to
interpretation: p-values for random data should be uniformly
distributed on [0,1)

Of course, now that I've done all this, I'm having doubts about its
utility. I'm not sure this method would be strong enough in cases that
need cryptographic random numbers (i.e. key generation). And it is
probably too slow to be used in applications where a PRNG would
suffice. What does that leave?

.... but I put some serious time into this, so by golly -- I'm gonna
tell you about it.

/*
   The CRC32 code is based upon work by Charles Michael Heard. He did
not affix any copyright to his original code. He should be contacted
before this is used for anything more than proof-of-concept.
*/

#include <stdlib.h>
#include <time.h>
#include <unistd.h> // this is needed for write(), not required by the
algo

unsigned char true_rand();

int main(int argc, char ** argv)
{
        size_t num = ~0;
        if (argc > 1)
                num = atoi(argv[1]);

        for (size_t i=0;i<num;++i){
                unsigned char c = true_rand();
                write(1,&c,1);
        }
        return 0;
}

const unsigned long polynomial = 0x04c11db7;
unsigned long crc_table[256];

void gen_crc_table()
{
        int i, j;
        unsigned long crc_accum;
        for ( i = 0; i < 256; i++ ){
                crc_accum = ( i << 24 );
                for ( j = 0; j < 8; j++ ){
                        if ( crc_accum & 0x80000000L )
                                crc_accum = ( crc_accum << 1 ) ^
polynomial;
                        else
                                crc_accum = ( crc_accum << 1 );
                }
                crc_table[i] = crc_accum;
        }
}

inline
unsigned long update_crc(unsigned long crc_accum,const void *
pData,unsigned long data_blk_size)
{
        const char * data_blk_ptr = static_cast<const char *>(pData);
        int i;
        static bool init=false;
        if (!init){
                gen_crc_table();
                init = true;
        }
        while (data_blk_size--){
                i = (( crc_accum >> 24) ^ *data_blk_ptr++ ) & 0xff;
                crc_accum = ( crc_accum << 8 ) ^ crc_table[i];
        }
        return crc_accum;
}

inline
unsigned char churn(const void * pData=0,size_t bytes=0) {
        static unsigned long ent=0; //entropy pool

        ent = update_crc(static_cast<unsigned long>(-1),&ent,sizeof(ent
));
        if (bytes && pData)
                ent = update_crc(ent,pData,bytes);
        return (~ent)&0xff;
}

unsigned char true_rand()
{
        unsigned char result = 0;

        for (int i=0;i<8;++i)
        {
                unsigned int counter=0;
                clock_t start = clock();
                do
                {
                        ++counter;// keep counting until the clock
changes
                }while (start == clock());

                result <<= 1;
                // left shift 1 bit

                result |= (counter&1);
                // put the LSB from the counter into the LSB of the
result
        }
        return churn(&result,1);
}

Here are the diehard test results for a 3MB file generated by the above
program on a linux box (Pentium 233, kernel 2.2.14,g++ 2.95.2,glibc
2.1.1).

If anyone is interested in getting the file or installing diehard (the
precompiled binaries didn't work for me), contact me (mborgerding @
acm.org) and I will help out.

Birthday spacings:
   The 9 p-values were
        .650702 .352101 .372355 .322484 .871127
        .593715 .926910 .815100 .929238
  A KSTEST for the 9 p-values yields .817223

BINARY RANK TEST for 6x8 matrices
   TEST SUMMARY, 25 tests on 100,000 random 6x8 matrices
 These should be 25 uniform [0,1] random variables:
     .034846 .668624 .867341 .322676 .063906
     .573906 .616073 .756396 .259063 .225803
     .004042 .917611 .375742 .014019 .593909
     .101089 .832640 .527469 .372356 .176146
     .205358 .746577 .293803 .314605 .721505
   brank test summary for rand.dat
       The KS test for those 25 supposed UNI's yields
                    KS p-value= .723423

THE BITSTREAM TEST
 BITSTREAM test results forrand.dat
 tst no 1: 142557 missing words, 1.51 sigmas from mean, p-value=
.93489
 tst no 2: 141747 missing words, -.38 sigmas from mean, p-value=
.35224
 tst no 3: 142267 missing words, .84 sigmas from mean, p-value=
.79833
 tst no 4: 142453 missing words, 1.27 sigmas from mean, p-value=
.89800
 tst no 5: 142019 missing words, .26 sigmas from mean, p-value=
.60112
 tst no 6: 141123 missing words, -1.84 sigmas from mean, p-value=
.03309
 tst no 7: 142181 missing words, .63 sigmas from mean, p-value=
.73720
 tst no 8: 141680 missing words, -.54 sigmas from mean, p-value=
.29604
 tst no 9: 142044 missing words, .31 sigmas from mean, p-value=
.62349
 tst no 10: 142355 missing words, 1.04 sigmas from mean, p-value=
.85113
 tst no 11: 141741 missing words, -.39 sigmas from mean, p-value=
.34705
 tst no 12: 141922 missing words, .03 sigmas from mean, p-value=
.51181
 tst no 13: 142160 missing words, .59 sigmas from mean, p-value=
.72096
 tst no 14: 141871 missing words, -.09 sigmas from mean, p-value=
.46432
 tst no 15: 141482 missing words, -1.00 sigmas from mean, p-value=
.15904

   Results for COUNT-THE-1's in successive bytes:
                               chisquare equiv normal p-value
 byte stream for rand.dat 2566.34 .938 .825937

PARKING LOT TEST
DPARK: result of ten tests on file rand.dat
            Of 12,000 tries, the average no. of successes
                 should be 3523 with sigma=21.9
            Successes: 3518 z-score: -.228 p-value: .409702
            Successes: 3522 z-score: -.046 p-value: .481790
            Successes: 3508 z-score: -.685 p-value: .246694
            Successes: 3520 z-score: -.137 p-value: .445521
            Successes: 3510 z-score: -.594 p-value: .276387
            Successes: 3525 z-score: .091 p-value: .536382
            Successes: 3532 z-score: .411 p-value: .659449
            Successes: 3515 z-score: -.365 p-value: .357445
            Successes: 3529 z-score: .274 p-value: .607947
            Successes: 3539 z-score: .731 p-value: .767486
           square size avg. no. parked sample sigma
             100. 3521.800 9.231
            KSTEST for the above 10: p= .697954

               This is the MINIMUM DISTANCE test
              for random integers in the file rand.dat
     Sample no. d^2 avg equiv uni
           5 .5021 .2219 .396247
          10 .8606 .4462 .578929
          15 .0062 .4712 .006250
          20 .0754 .5142 .072955
          25 2.5621 .6595 .923843
          30 .5615 .6905 .431277
          35 1.9744 .7447 .862526
          40 .9322 .7300 .608140
          45 .0691 .7822 .067082
          50 .3137 .7939 .270420
          55 4.0357 .8903 .982682
          60 .1584 .9124 .147175

3DSPHERES test for file rand.dat p-value= .598040

OVERLAPPING SUMS
                Test no. 1 p-value .226889
                Test no. 2 p-value .148903
                Test no. 3 p-value .894253
                Test no. 4 p-value .922038
                Test no. 5 p-value .102995
                Test no. 6 p-value .792611
                Test no. 7 p-value .143711
                Test no. 8 p-value .819030
                Test no. 9 p-value .655024
                Test no. 10 p-value .588361
   Results of the OSUM test for rand.dat
        KSTEST on the above 10 p-values: .307924

           The RUNS test for file rand.dat
     Up and down runs in a sample of 10000
_________________________________________________
                 Run test for rand.dat :
       runs up; ks test for 10 p's: .575118
     runs down; ks test for 10 p's: .444705
                 Run test for rand.dat :
       runs up; ks test for 10 p's: .018677
     runs down; ks test for 10 p's: .285316


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk