mux/src/svdrand.cpp

Go to the documentation of this file.
00001 // svdrand.cpp -- Random Numbers.
00002 //
00003 // $Id: svdrand.cpp,v 1.7 2006/01/07 07:44:46 sdennis Exp $
00004 //
00005 // MUX 2.4
00006 // Copyright (C) 1998 through 2004 Solid Vertical Domains, Ltd. All
00007 // rights not explicitly given are reserved.
00008 //
00009 // Random Numbers from Makoto Matsumoto and Takuji Nishimura.
00010 //
00011 #include "copyright.h"
00012 #include "autoconf.h"
00013 #include "config.h"
00014 #include "externs.h"
00015 
00016 #include "timeutil.h"
00017 
00018 #include "svdhash.h"
00019 #include "svdrand.h"
00020 
00021 #ifdef WIN32
00022 #include <wincrypt.h>
00023 typedef BOOL WINAPI FCRYPTACQUIRECONTEXT(HCRYPTPROV *, LPCTSTR, LPCTSTR, DWORD, DWORD);
00024 typedef BOOL WINAPI FCRYPTRELEASECONTEXT(HCRYPTPROV, DWORD);
00025 typedef BOOL WINAPI FCRYPTGENRANDOM(HCRYPTPROV, DWORD, BYTE *);
00026 #else // WIN32
00027 #include <sys/stat.h>
00028 #include <sys/types.h>
00029 #include <fcntl.h>
00030 #include <unistd.h>
00031 #endif // WIN32
00032 
00033 // Seed the generator.
00034 //
00035 static void sgenrand(UINT32);
00036 static void sgenrand_from_array(UINT32 *, int);
00037 
00038 // Returns a random 32-bit integer.
00039 //
00040 static UINT32 genrand(void);
00041 
00042 #define NUM_RANDOM_UINT32 1024
00043 
00044 bool bCryptoAPI = false;
00045 static bool bSeeded = false;
00046 void SeedRandomNumberGenerator(void)
00047 {
00048     if (bSeeded) return;
00049     bSeeded = true;
00050 
00051     UINT32 aRandomSystemBytes[NUM_RANDOM_UINT32];
00052     unsigned int nRandomSystemBytes = 0;
00053 
00054 #ifdef HAVE_DEV_URANDOM
00055     // Try to seed the PRNG from /dev/urandom
00056     // If it doesn't work, just seed the normal way
00057     //
00058     int fd = open("/dev/urandom", O_RDONLY);
00059 
00060     if (fd >= 0)
00061     {
00062         int len = read(fd, aRandomSystemBytes, sizeof aRandomSystemBytes);
00063         close(fd);
00064         if (len > 0)
00065         {
00066             nRandomSystemBytes = len/sizeof(UINT32);
00067         }
00068     }
00069 #endif // HAVE_DEV_URANDOM
00070 #ifdef WIN32
00071     // The Cryto API became available on Windows with Win95 OSR2. Using Crypto
00072     // API as follows lets us to fallback gracefully when running on pre-OSR2
00073     // Win95.
00074     //
00075     bCryptoAPI = false;
00076     HINSTANCE hAdvAPI32 = LoadLibrary("advapi32");
00077     if (hAdvAPI32)
00078     {
00079         FCRYPTACQUIRECONTEXT *fpCryptAcquireContext;
00080         FCRYPTRELEASECONTEXT *fpCryptReleaseContext;
00081         FCRYPTGENRANDOM *fpCryptGenRandom;
00082 
00083         // Find the entry points for CryptoAcquireContext, CrytpoGenRandom,
00084         // and CryptoReleaseContext.
00085         //
00086         fpCryptAcquireContext = (FCRYPTACQUIRECONTEXT *)
00087             GetProcAddress(hAdvAPI32, "CryptAcquireContextA");
00088         fpCryptReleaseContext = (FCRYPTRELEASECONTEXT *)
00089             GetProcAddress(hAdvAPI32, "CryptReleaseContext");
00090         fpCryptGenRandom = (FCRYPTGENRANDOM *)
00091             GetProcAddress(hAdvAPI32, "CryptGenRandom");
00092 
00093         if (  fpCryptAcquireContext
00094            && fpCryptReleaseContext
00095            && fpCryptGenRandom)
00096         {
00097             HCRYPTPROV hProv;
00098 
00099             if (  fpCryptAcquireContext(&hProv, NULL, NULL, PROV_DSS, 0)
00100                || fpCryptAcquireContext(&hProv, NULL, NULL, PROV_DSS, CRYPT_NEWKEYSET))
00101             {
00102                 if (fpCryptGenRandom(hProv, sizeof aRandomSystemBytes,
00103                     (BYTE *)aRandomSystemBytes))
00104                 {
00105                     nRandomSystemBytes = NUM_RANDOM_UINT32;
00106                     bCryptoAPI = true;
00107                 }
00108                 fpCryptReleaseContext(hProv, 0);
00109             }
00110         }
00111         FreeLibrary(hAdvAPI32);
00112     }
00113 #endif // WIN32
00114 
00115     if (nRandomSystemBytes >= sizeof(UINT32))
00116     {
00117         unsigned int i;
00118         for (i = 0; i < nRandomSystemBytes; i++)
00119         {
00120             aRandomSystemBytes[i] &= 0xFFFFFFFFUL;
00121         }
00122         sgenrand_from_array(aRandomSystemBytes, nRandomSystemBytes);
00123         return;
00124     }
00125 
00126     // Determine the initial seed.
00127     //
00128     CLinearTimeAbsolute lsaNow;
00129     lsaNow.GetUTC();
00130     INT64 i64Seed = lsaNow.Return100ns();
00131     int pid = getpid();
00132 
00133     UINT32 nSeed = CRC32_ProcessBuffer(0, &i64Seed, sizeof(INT64));
00134     nSeed = CRC32_ProcessBuffer(nSeed, &pid, sizeof(pid));
00135 
00136     if (nSeed <= 1000)
00137     {
00138         nSeed += 22261048;
00139     }
00140 
00141     // ASSERT: 1000 < nSeed
00142 
00143     sgenrand(nSeed);
00144 }
00145 
00146 // RandomINT32 -- return a long on the interval [lLow, lHigh]
00147 //
00148 INT32 RandomINT32(INT32 lLow, INT32 lHigh)
00149 {
00150     // Validate parameters
00151     //
00152     if (lHigh < lLow)
00153     {
00154         return -1;
00155     }
00156     else if (lHigh == lLow)
00157     {
00158         return lLow;
00159     }
00160 
00161     UINT32 x = lHigh-lLow;
00162     if (INT32_MAX_VALUE < x)
00163     {
00164         return -1;
00165     }
00166     x++;
00167 
00168     // We can now look for an random number on the interval [0,x-1].
00169     //
00170 
00171     // In order to be perfectly conservative about not introducing any
00172     // further sources of statistical bias, we're going to call getrand()
00173     // until we get a number less than the greatest representable
00174     // multiple of x. We'll then return n mod x.
00175     //
00176     // N.B. This loop happens in randomized constant time, and pretty
00177     // damn fast randomized constant time too, since
00178     //
00179     //      P(UINT32_MAX_VALUE - n < UINT32_MAX_VALUE % x) < 0.5, for any x.
00180     //
00181     // So even for the least desireable x, the average number of times
00182     // we will call getrand() is less than 2.
00183     //
00184     UINT32 n;
00185     UINT32 nLimit = UINT32_MAX_VALUE - (UINT32_MAX_VALUE%x);
00186 
00187     do
00188     {
00189         n = genrand();
00190     } while (n >= nLimit);
00191 
00192     return lLow + (n % x);
00193 }
00194 
00195 /* A C-program for MT19937, with initialization improved 2002/2/10.*/
00196 /* Coded by Takuji Nishimura and Makoto Matsumoto.                 */
00197 /* This is a faster version by taking Shawn Cokus's optimization,  */
00198 /* Matthe Bellew's simplification, Isaku Wada's real version.      */
00199 
00200 /* Before using, initialize the state by using init_genrand(seed)  */
00201 /* or init_by_array(init_key, key_length).                         */
00202 
00203 /* This library is free software.                                  */
00204 /* This library is distributed in the hope that it will be useful, */
00205 /* but WITHOUT ANY WARRANTY; without even the implied warranty of  */
00206 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.            */
00207 
00208 /* Copyright (C) 1997, 2002 Makoto Matsumoto and Takuji Nishimura. */
00209 /* Any feedback is very welcome.                                   */
00210 /* http://www.math.keio.ac.jp/matumoto/emt.html                    */
00211 /* email: matumoto@math.keio.ac.jp                                 */
00212 
00213 #define N 624
00214 #define M 397
00215 #define MATRIX_A 0x9908b0dfUL
00216 #define UMASK 0x80000000UL // most significant w-r bits
00217 #define LMASK 0x7fffffffUL // least significant r bits
00218 #define MIXBITS(u,v) ( ((u) & UMASK) | ((v) & LMASK) )
00219 #define TWIST(u,v) ((MIXBITS(u,v) >> 1) ^ ((v)&1UL ? MATRIX_A : 0UL))
00220 
00221 static UINT32 mt[N];
00222 static int left = 1;
00223 static UINT32 *next;
00224 
00225 // initializes mt[N] with a seed.
00226 //
00227 static void sgenrand(UINT32 nSeed)
00228 {
00229     int j;
00230     mt[0] = nSeed & 0xffffffffUL;
00231     for (j = 1; j < N; j++)
00232     {
00233         // See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier.
00234         // In the previous versions, MSBs of the seed affect
00235         // only MSBs of the array mt[].
00236         // 2002/01/09 modified by Makoto Matsumoto.
00237         //
00238         mt[j] = 1812433253UL * (mt[j-1] ^ (mt[j-1] >> 30)) + j;
00239         mt[j] &= 0xffffffffUL;  // for >32 bit machines.
00240     }
00241     left = 1;
00242 }
00243 
00244 // initialize by an array with array-length
00245 // init_key is the array for initializing keys
00246 // key_length is its length
00247 //
00248 static void sgenrand_from_array(UINT32 *init_key, int key_length)
00249 {
00250     sgenrand(19650218UL);
00251     int i = 1;
00252     int j = 0;
00253     int k = (N > key_length ? N : key_length);
00254     for (; k; k--)
00255     {
00256         mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
00257               + init_key[j] + j;
00258         mt[i] &= 0xffffffffUL; // for > 32-bit machines.
00259         i++;
00260         j++;
00261         if (i >= N)
00262         {
00263             mt[0] = mt[N-1];
00264             i = 1;
00265         }
00266         if (j >= key_length)
00267         {
00268             j = 0;
00269         }
00270     }
00271     for (k = N-1; k; k--)
00272     {
00273         mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) - i;
00274         mt[i] &= 0xffffffffUL; // for > 32-bit machines.
00275         i++;
00276         if (i >= N)
00277         {
00278             mt[0] = mt[N-1];
00279             i = 1;
00280         }
00281     }
00282 
00283     mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
00284     left = 1;
00285 }
00286 
00287 static void next_state(void)
00288 {
00289     UINT32 *p = mt;
00290     int j;
00291 
00292     if (!bSeeded)
00293     {
00294         SeedRandomNumberGenerator();
00295     }
00296 
00297     for (j = N-M+1; --j; p++)
00298     {
00299         *p = p[M] ^ TWIST(p[0], p[1]);
00300     }
00301 
00302     for (j = M; --j; p++)
00303     {
00304         *p = p[M-N] ^ TWIST(p[0], p[1]);
00305     }
00306 
00307     *p = p[M-N] ^ TWIST(p[0], mt[0]);
00308 
00309     left = N;
00310     next = mt;
00311 }
00312 
00313 // generates a random number on the interval [0,0xffffffff]
00314 //
00315 static UINT32 genrand(void)
00316 {
00317     UINT32 y;
00318 
00319     if (--left == 0)
00320     {
00321         next_state();
00322     }
00323     y = *next++;
00324 
00325     // Tempering.
00326     //
00327     y ^= (y >> 11);
00328     y ^= (y << 7) & 0x9d2c5680UL;
00329     y ^= (y << 15) & 0xefc60000UL;
00330     y ^= (y >> 18);
00331 
00332     return y;
00333 }

Generated on Mon May 28 04:40:11 2007 for MUX by  doxygen 1.4.7