## True Random Number Generators on the Web

Maple

In a series of posts now imported to the Maplesoft blog (starting here), I have been talking about pseudo-random number sequences, but since part of what kicked off this series was a paper on true random number generation (with LASERS!) I thought I would share some routines I wrote that alllow you to use the two main true random number sources available on the web (neither using lasers, sadly).

The most popular true random number source on the web is random.org.  It uses atmospheric noise to generate its random sequences.  Specifically, it uses radio receivers, tuned between stations, in several different countries to pick up atmospheric noise, which is then used to generate the random bits.  To ensure quality of their numbers, they run, in real-time, many of the tests I have described in this series of posts.  It is a pretty fast service with a pretty good API, so it was easy to write the following interface to get random bits into Maple using the ?Sockets package.  The arguments to the procedure RandomDotOrg basically mirror that API and should be self explanatory.

```RandomDotOrg := proc( rangemax::integer:=1000000000,
rangemin::integer:=0,
{number::posint:=1, base::posint:=10}, \$)
local sock, query, quota, output, line, tmp;

try
# Open socket
sock:=Sockets:-Open("random.org",80);

# check quota
query := "GET /quota/?format=plain \n\n";
Sockets:-Write(sock, query);
Sockets:-Close(sock);

quota := parse(StringTools:-Chomp(line));
if quota < 0 then
error `out of random.org quota`;
end if;

sock:=Sockets:-Open("random.org",80);
query := cat("GET /integers/?num=",number,"&min=",rangemin,"&max=",rangemax-1,"&col=1&base=",base,                          "&format=plain&rnd=new \n\n");
Sockets:-Write(sock, query);

if tmp[1..12] = "HTTP/1.1 400" then
error `connection error: HTTP/1.1 400 Bad Request`;
elif tmp[1..12] = "HTTP/1.1 403" then
error `connection error: HTTP/1.1 403 Service Unavailable`;
end if;

line := "":
while tmp <> false do
line := cat(line,tmp);
end do;

output := StringTools:-Split(StringTools:-Chomp(line));
output := map(parse, output);

catch:
error
finally
Sockets:-Close(sock);
end try;

return op(output);

end proc:
```

Of course, to prevent overuse, they limit each IP address to 200,000 bits per day.  So, if you are doing a big Monte-Carlo simulation, you would probably be better off just using the service to generate a random seed and use a good PRNG for the rest of the sequence.

Here is a how you could use this procedure to efficiently generate a 10,000 bit random sequence

```(**) L1 := map((op@Bits:-Split), [RandomDotOrg(2^25-1, number=417)], bits=24);
```

The other online service for true random numbers is HotBits from Fourmi Lab.  It uses the randomness of the radioactive decay of atoms of Cæsium-137 (here is a detailed description of how it is done). Its service is a lot slower that random.org, so it is best to use it generate small sequences or seeds.

The Hotbits API is a little more complicated, so I have to deploy ?XMLTools to parse the output I get from the ?Sockets package

```HotBits := proc(bytes::posint:=8, {format::string:="decimal"}, \$ )
local sock, query, line, tmp, xmldata, rinfo, breq, bret, reqquota, bytequota, rdata, output;

if bytes >= 1000 then
error "invalid input: maximum request size is 999 bytes";
end if;

try
# Open socket
sock:=Sockets:-Open("www.fourmilab.ch",80);

query := cat("GET /cgi-bin/Hotbits?nbytes=",bytes,"&fmt=xml \n\n");
Sockets:-Write(sock, query);

if tmp[1..12] = "HTTP/1.1 400" then
error `connection error: HTTP/1.1 400 Bad Request`;
elif tmp[1..12] = "HTTP/1.1 403" then
error `connection error: HTTP/1.1 403 Service Unavailable`;
end if;

line := "":
while tmp <> false do
line := cat(line,tmp);
end do;

catch:
error
finally
Sockets:-Close(sock);
end try;

if line="" then
error `did not receive any data from server`;
end if;

# line is XML
xmldata := XMLTools:-ParseString(line);

# check that bytes requested = bytes returned
rinfo := XMLTools:-GetChildByName(xmldata, "request-information")[1];
breq := parse(XMLTools:-TextText(XMLTools:-SelectContent(XMLTools:-IsText,                              XMLTools:-GetChildByName(rinfo, "bytes-requested")[1])[1]));
bret := parse(XMLTools:-TextText(XMLTools:-SelectContent(XMLTools:-IsText,                              XMLTools:-GetChildByName(rinfo, "bytes-returned")[1])[1]));

if breq > bret then
WARNING("Returning Fewer bytes than requested");    end if;

# process random bits
rdata := XMLTools:-GetChildByName(xmldata, "random-data")[1];
rdata := XMLTools:-TextText(XMLTools:-SelectContent(XMLTools:-IsText, rdata)[1]);
rdata := remove(type, StringTools:-Split(StringTools:-Trim(rdata)), "");

if format[1..3]="hex" then
output := map(convert, rdata, 'name');
elif format[1..3]="bit" or format[1..3]="bin" then
output := map(convert, rdata, 'decimal', 16);
output := map(op@Bits:-Split, output, bits=8);
elif format="raw" then
output := rdata;
else
WARNING("invalid format specifier; valid formats are decimal, hex, binary, and raw");
output := map(convert, rdata, 'decimal', 16);
end if;

return output;

end proc:```

The arguments to HotBits are different, again, to mirror the API. Here is how you might generate a sequence of 10,000 bits by making two requests for 625 bytes worth of bits:

`(**) L2 := [seq(op(HotBits(625, format="bits")), i=1..2)];`

For your convience, here are the two procedures in a worksheet that uses each to generate images from random bit sequences: WebRandom.mw.

If you want to play with these generates together with some randomness tests, keep in mind that both services impose quotas and it is easy to run out.

﻿