/* * Physically random numbers (very nearly uniform) * D. P. Mitchell * Modified by Matt Blaze 2/95 * Modified to avoid Linux bug iang 23-10-98 * Modified by Shin Motomiya 3/01 */ /* * The authors of this software are Don Mitchell and Matt Blaze. * Copyright (c) 1995 by AT&T. * Permission to use, copy, and modify this software without fee * is hereby granted, provided that this entire notice is included in * all copies of any software which is or includes a copy or * modification of this software and in all copies of the supporting * documentation for such software. * * This software may be subject to United States export controls. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ /* * WARNING: depending on the particular platform, truerand() output may * be biased or correlated. In general, you can expect about 16 bits of * "pseudo-entropy" out of each 32 bit word returned by truerand(), * but it may not be uniformly diffused. You should therefore run * the output through some post-whitening function (like MD5 or DES or * whatever) before using it to generate key material. (RSAREF's * random package does this for you when you feed truerand() bits to the * seed input function.) * * Test these assumptions on your own platform before fielding a system * based on this software or these techniques. * * This software seems to work well (at 16 bits per truerand() call) on * a Sun Sparc-20 under SunOS 4.1.3 and on a P100 under BSDI 2.0. You're * on your own elsewhere. * * [iang 23-10-98] * Rewritten to eliminate use of setenv (which was causing * crashes on Linux). Not clear what use of setenv gained, * it apparently added nothing to the count. * should really check with authors... * * What truerand() does: it times the clock ticks on Unix. * These ticks run at 50 or 60Hz, and the timer is set to * include one each time. A clock tick causes an interrupt * that dives through the admin code of the kernel. If the * the system has any load whatsoever, this time should be of * variable length. * * Note that the delay is set for 60Hz, not 50Hz. Should get * the frequency from the system first. */ /* * * Win32 stuff written by Reini Urban based on cygwin/winsup/window.cc. * Copyright 1996, 1997, 1998, 1999 Cygnus Solution * Copyright 2000 Reini Urban * This compiles, but doesn't work yet correctly. * http://xarch.tu-grat.ac.at/home/rurban/software/perl */ #include #include #ifdef _WIN32 #include #include /* struct timeval { long tv_sec; long tv_usec; }; */ #define ITIMER_REAL 0 #define ITIMER_VIRTUAL 1 #define ITIMER_PROF 2 struct itimerval { struct timeval it_interval; struct timeval it_value; }; #else #include #endif /* _WIN32 */ #include #include #include #include "truerand.h" static jmp_buf env; static unsigned count; /* assume unsigned is >= 32 bits */ static unsigned ocount; static unsigned buffer; static int triples; static int spin; #ifdef _WIN32 #define SIGALRM SIGINT /* oops */ /* from cygwin/winsup/window.cc with some simplifications. */ static UINT timer_active = 0; static struct itimerval itv; static DWORD start_time; int setitimer (which, value, oldvalue) int which; const struct itimerval *value; struct itimerval *oldvalue; { UINT elapse; if (which != ITIMER_REAL) { strerror (EINVAL); return -1; } if (timer_active) { KillTimer (NULL, timer_active); timer_active = 0; } if (oldvalue) *oldvalue = itv; if (value == NULL) { strerror (EFAULT); return -1; } itv = *value; elapse = itv.it_value.tv_sec * 1000 + itv.it_value.tv_usec / 1000; if (elapse == 0) return 0; if (!(timer_active = SetTimer (NULL, 1, elapse, NULL))) { strerror (0); return -1; } start_time = GetTickCount (); return 0; } #endif /* _WIN32 */ static void tick(); static void catch() { if (count) { spin = 0; /* stop spinning */ } else { tick(); /* 0 mucks up algorithm, again */ } return ; } static void tick() { struct itimerval it, oit; (void) signal(SIGALRM, catch); timerclear(&it.it_interval); it.it_value.tv_sec = 0; it.it_value.tv_usec = 16665; /* get at least one clock tick */ /* note on 50Hz, will miss a few */ if (setitimer(ITIMER_REAL, &it, &oit) < 0) perror("tick"); } void blackjack() { count = 0; spin = 1; tick(); while (spin) /* reset when signal arrives */ count++; /* about 1 MHz on VAX 11/780 */ count ^= (count>>3) ^ (count>>6) ^ ocount; ocount = count & 0x7; /* store last 3 bits */ buffer = (buffer<<3) ^ count; } unsigned long truerand() { count = 0; for (triples = 0; triples < 11; triples++) /* 11 * 3 > 32 */ blackjack(); return buffer; } int n_truerand(n) int n; { int slop, v; slop = 0x7FFFFFFF % n; do { v = truerand() >> 1; } while (v <= slop); return v % n; }