/*\ * RRAND RNG - Ruptor's Fast True Random Number Generator, v3.0 based on RUPT64x2-512/2 * http://cryptolib.com/crypto/rrand * Copyright (c) 1992-2010 Marcos el Ruptor * Released to public domain. \*/ #ifndef _CRT_SECURE_NO_DEPRECATE #define _CRT_SECURE_NO_DEPRECATE 1 #endif #include #include #include "rrand.h" #if (defined(_MSC_VER)||defined(__INTEL_COMPILER)) #if (_MSC_VER >= 1300) unsigned __int64 __cdecl _rotr64 (unsigned __int64, int); #pragma intrinsic (_rotr64) #else #define _rotr64(x,n) ((((ulonglong)(x))<<(n&63))|(((ulonglong)(x))>>((0-(n))&63))) #endif #else #define _rotr64(x,n) ((((ulonglong)(x))<<(n&63))|(((ulonglong)(x))>>((0-(n))&63))) #endif #ifndef __forceinline #if defined(__GNUC__) #define __forceinline __inline__ #elif defined(__MACH__) && defined(__APPLE__) #define __forceinline __inline #endif #endif #if (defined(_MSC_VER)||defined(__WATCOMC__)||defined(INTEL_COMPILER))&&(_MSC_FULL_VER >= 140040310) unsigned __int64 __rdtsc (void); #pragma intrinsic(__rdtsc) #endif static __forceinline ulonglong clock_counter (void) { #if defined(_MSC_VER)||defined(__WATCOMC__)||defined(INTEL_COMPILER) #if (_MSC_FULL_VER >= 140040310) return __rdtsc(); #else __asm rdtsc #endif #elif defined(__i386__) ulonglong q; __asm__ __volatile__("rdtsc\n\t" : "=A" (q)); return q; #elif defined(__x86_64__) ulonglong l,h; __asm__ __volatile__ ("rdtsc" : "=a" (l), "=d" (h)); return (l + (h << 32)); #elif defined(__sparc__) ulonglong tick; __asm__ __volatile__ ("rd %%tick, %0" : "=r" (tick)); return tick; #elif defined(__alpha__) ulonglong cc; __asm__ __volatile__ ("rpcc %0" : "=r" (cc)); return cc; #elif defined(__ia64__) ulonglong itc; __asm__ __volatile__ ("mov %0 = ar.itc" : "=r" (itc)); return itc; #elif defined(__powerpc__) || defined(__ppc__) ulonglong tbl, tbu0, tbu1; do { __asm__ ("mftbu %0" : "=r" (tbu0)); __asm__ ("mftb %0" : "=r" (tbl )); __asm__ ("mftbu %0" : "=r" (tbu1)); } while (tbu0 != tbu1); return tbl; #else struct timeval tv; gettimeofday (&tv, NULL); return (tv.tv_usec); #endif } #define RUPT(n,m,k) (\ rr->pool[(n+2)m]^=f=_rotr64(2*rr->pool[(n+1)m]^rr->pool[(n+4)m]^rr->d0^rr->r++,16)*9,rr->d0^=f^rr->pool[(n )m],\ rr->pool[(n+3)m]^=f=_rotr64(2*rr->pool[(n )m]^rr->pool[(n+5)m]^rr->d1^rr->r++,16)*9,rr->d1^=f^rr->pool[(n+1)m]^(k)) #define rrand_reseed(rr,times,seed) \ { \ uint i, n; \ for (i = 0; i < (times); i++) \ { \ for (n = 0; n < RRAND_SIZE-4; n+=4) RUPT(n,,seed),RUPT(n+2,,clock_counter()); \ RUPT (RRAND_SIZE-4,%RRAND_SIZE,clock_counter()),RUPT(RRAND_SIZE-2,%RRAND_SIZE,seed); \ } \ } void rrand_init (rrand_state * const rr) { ulonglong f; rrand_reseed (rr, (65536/RRAND_SIZE)|3, clock_counter()); } #define rr ((rrand_state *) vr) ulonglong rrand (void * const vr) { uint o = rr->offset; ulonglong f; if (o >= RRAND_SIZE-4) /* slow paranoid version */ { rrand_reseed (rr, 1, clock_counter ()); /* completely reseeding the state once, just in case. there is no need for it to refill the entire state with tons of entropy, just refilling it a bit. long reseeding is advised only before generation of exceptionally sensitive large secret keys. */ rr->offset = o = 0; } RUPT (o,,0); RUPT (o+2,,clock_counter()); rr->offset = o+4; return rr->d1; } #undef rr #ifndef RAND_TEST #include static ulonglong buf[65536]; int main (int argc, char *argv[]) { FILE *f; time_t t; int i, j, k; rrand_state rr; ulonglong q; if (argc < 2) { fprintf (stderr, "usage: %s \n", argv[0]); return 1; } if ((f = fopen (argv[1], "wb+")) == NULL) { fprintf (stderr, "failed to open '%s' for writing.\n", argv[1]); return 1; } rrand_init (&rr); /* can also start a parallel thread reseeding the rr state every few ms, just in case */ t = time (NULL); for (i = 0, k = 5120/sizeof(ulonglong); i < k; i++) { q = clock_counter (); /* to measure the PRNG speed */ for (j = 0; j < 65536; j++) buf[j] = rrand (&rr); /* we simply call rrand continuously just as we would call random(), but this one is 12 CPB on x64, 45 CPB on x86 in plain C */ q = clock_counter () - q; /* to measure the average PRNG speed in CPB */ fwrite (buf, 1, sizeof(buf), f); printf ("\rGenerating 320Mb of data in file '%s'... %04.1f%% done... [%4lu cycles per byte]", argv[1], (100*(float)(i+1))/k, q/(65536*sizeof(ulonglong))); fflush (stdout); } if (t == time (NULL)) t--; printf ("\rGenerating 320Mb of data in file '%s'... done (%u bytes/sec)\n", argv[1], (5120*65536)/(time(NULL)-t)); fclose (f); return 0; } #endif