Home Page

A Deterministic True Random Number Generator;

Is it completely impossible to deterministically generate truly random numbers, or is it only almost completely impossible? I am using OS/2 Rexx to increment a counter over a variable interval and converting that to a random byte from 0 to 255. To smooth the distribution, two queries are made per byte. Each of the 256 possible bytes from the first query is converted to a different interval from 10 to 265 milliseconds. On my slow 1 GigaHertz processor, I get about 133 bytes per minute. But are they random and randomly distributed?

My cursory check is with the program 'Ent' ( ). Walker, John. 2008. Ent: A Pseuorandom Number Sequence Test Program. An OS/2 binary is available via Hobbes.NMSU.EDU. I compared a run of 19125 bytes made with my RexxMakeRandomBytes (Experiment) script to a run obtained from the trusted Rexx Entropy Gathering Daemon (Random Daemon) ( ). O'Connor, Russell. 2001. Rexx Entropy Gathering Daemon for OS/2.

Results
Item Experiment Random Daemon Perfect Score
Entropy +7.98… +7.99… +8
Compress- %0 %0 %0
Chi² #/% +269.73; %25.15 +230.76; %85.99 +%10 to %90*
Mean +127.07… +127.12… +127.5
Monte Carlo Pi +3.107… +3.144… +3.141…
Serial Corr. +0.001… -0.007… +0
* %5 to %10 or %90 to %95 is almost suspect; %1 to %5 or %95 to %99 is suspect; %<1 or %>99 is nonrandom.

The results are too good to be true. I don't trust my script enough to rely on it. I only use it as an extra input to the Rexx Random Daemon, where it can do no harm.

What's the source of randomness?

I hypothesize that the CPU speed and availability are sufficiently variable to effectively be a noise source. Measuring the count reached in an interval captures that noise. I also imagine that's it's digitizing time in much the same way that pulse code modulation digitizes voice. Any sampling process introduces sampling noise, sometimes called quantization error. And noise is what we're after. It's just difficult to believe that such a simple script could output any random data at all.

Is this random number source fatally flawed?

In the first place, when I first wrote this, it was April 1st. In the second place, we know it can't be this simple to produce truly random numbers. If it was, everybody would be doing it. Nobody would go to the trouble of using the Entropy Gathering daemons (Perl, Rexx). Nobody would worry about the reliability of the Linux random devices. Mozilla-based software wouldn't rummage around the file system after a startup looking for entropy. Intel wouldn't include a semiconductor random number generator. People wouldn't sell, let alone buy, true random number generator plug-in cards.

There has to be a flaw. Why doesn't Ent see it? Legions of mathematicians, cryptographers, and computer scientists should be able to thoroughly debunk this script -- but can they do it in English that even I can understand? That is the question.

MakeRandomBytes.cmd (untrusted)


/* MakeRandomBytes */
x=time('r')
bldlevel=,
'@#Walt_Gregg_Juneau_AK_US:2016.2021.12.04#@MakeRandomBytes (Dubious)'
parse var bldlevel '@#' author ':'oyear '.' year '.' yearday '#@' name '-' desc
parse source SYSTEM CALLTYPE FQN
NAME=filespec('name',FQN)
NAME=translate(substr(NAME,1,lastpos('.',NAME)-1))
call RxFuncAdd 'SysSleep','RexxUtil','SysSleep'
if calltype='COMMAND' then parse arg BYTES
else BYTES=arg(1)
Select
  When BYTES='' then signal help
  When BYTES='/?' then signal help
  When datatype(BYTES,'w')\=1 then signal help
  When BYTES<1 then signal help
  otherwise nop
end
STRING=''
do i=1 to BYTES
  STRING=STRING||GetSmoothedByte()
  if calltype='COMMAND' then do
    SIZE=length(string)
    PERCENT=format(SIZE/BYTES*100,3,2)
    say SIZE 'chars of' BYTES '-' PERCENT ||'% done'
  end
end
if calltype='COMMAND' then x=charout('stderr',STRING)
else return STRING
if calltype='COMMAND' then do
  say
  say Length(STRING) 'chars in' time('e') 'sec'
exit 0
/*
Smooth the distribution of the 256 sided dice.
One call to GetLoadedByte set the measurement interval.
The next call gets a less skewed data byte.
*/
GetSmoothedByte: procedure
INTERVAL=GetLoadedByte() /* Character 0-255 */
INTERVAL=c2d(INTERVAL)    /* Decimal 0-255 */
INTERVAL=(INTERVAL+10)/1000 /* Convert to .010 to .265 */
return GetLoadedByte(INTERVAL)
/*
Get a random but loaded byte.
Count from 0 over the interval to capture randomness.
Source: Speed, CPU availability, quantization error.
Return result as byte 0 to 255.
*/
GetLoadedByte: procedure
parse arg INTERVAL
if INTERVAL='' then INTERVAL=0.010
call SysSleep 0.125 /* Limit CPU Load to some 50% */
count=0
x=time('r')
do forever
  count=count+1
  if time('e')>INTERVAL then leave
end
dec=count//256 /* Reduce result to 0 to 255 */
char=d2c(dec) /* Return as byte */
return char
/*
HELP
*/
help:
say 'Use the' NAME 'command to generate unpredictable random bytes.'
say 'Command Syntax:'
say ' ' NAME '#' '[2>[drive:][\path\]filename]'
say 'Function Syntax:'
say '  STRING='||NAME||'(#)'
say 'where:'
say '  #      is the number of unpredictable random bytes to generate.'
say '  2>...  specifies a target file to receive the bytes.'
say '  STRING is a variable to receive the bytes.'
say 
say 'Copyright walt.gregg.juneau.ak.us 2016; License: attribution'
say 'share-alike; Details: apache.org/licenses/LICENSE-2.0.'
say 'Absolutely no warranties, express or implied.'
say
say 'THERE CAN BE NO ASSURANCE THAT THESE BYTES ARE EITHER'
say 'UNPREDICTABLE OR MATHEMATICALLY RANDOM.'
exit 0

📧 Send Comment Walt.Gregg.Juneau.AK.US/contact
🏡 Home Page Walt.Gregg.Juneau.AK.US
  Global Statistics   gs.statcounter.com