Quantum Dice EaaS demo

Contents:

Introduction

The Quantum Dice Entropy as a Service facility is intended for demonstrating the use of quantum randomness, particularly in two situations

  1. A small amount of randomness is needed for cryptography
  2. A large amount of randomness is needed for simulations

Accessing the EaaS server

You will need:

Please note that the demo server imposes limits on the rate at which it will supply random bits. This is typically around 1Mb/s.

Running the python demo

The python demo is the simplest to run as it does not require anything to be built. Unpack the software into a convenient directory. In that directory you now have:

The qdremdemo program fetches and prints out various forms of randomness: raw bytes, integers, uniformly distributed floating point numbers, and normally distributed floating point numbers.

python3 qdremdemo.py 20.100.202.187 33399 demosrv-cert.pem cli-cert.pem cli-key.pem
and it should print something like this:
256 random bytes: b'"s|\xc0\x98\xcf\xae\x0e\x8b\xb2VZ\x9epb\x89\x94\xc4L\x88\xb
4\x87q\x9e\xd6:\xd6\xef\xa2\xafo\xf7\x9e\x847\x92*\x842\xf0\x7f\xfa_\x89\xe0\x1
4\xe2\xe8\xef\xbf\xde\x94\xd1\xfc\xee\xf1\x8c\xfe\x06\x00I4\x8e!\x06D\xb3=|p\x0
7\xda\xf4p\x7f\xcec\x05\x9276\xf9\x1c\'\xd2\xe8\x99\xaf\xb8\x1c\x89\xd9\x8e3\xa
3\xff^\x7f.~B@\xc2O\x80\x88\xaf\xb8%\x1c#k$\x1c\xb8t\xa9e\x11\x10;\x0fL\xdc\x9b
\xaa\x88\xa4*\xcbp\xd0X\x12\x8d\x8a\x1e\xc0\xba\xd5\x1e5\x1e\xb8\x8a\x06\xe2HW\
xd8\xcf\x01\xb2\xb1\x13\xa0?\xbd\xb9\xba\x10\x86\x14\x82\xe6\xc1->\\\xb9\xe3\xa
2\x0b\xe9!\xab\x98I\xf0\x01\xbc\x01"3f\xac\xa8-\xb5\xf6\xed]\xb2\xb1"\xfe\xfe\x
e8\xb5\xe3Q;9\xf8\t\x9b\xca$\x97\x9f\xf3\xec\xb6\x9f\xf56\x19\xb1u\xber\xe1\xec
\x1f\\\xdb(\x97\xc5%\xf2<b01\xf4&{I\xe1\xb8+]\xb5\x95o\xe1[2\x19 \x02\xb7\x80G\
x8c'
Random 32-bit integers:
        7536378
        1856549
        6399506
        8269273
        5024114
        791705
        5318393
        2693547
Random floating point numbers from uniform distribution [0.0, 1.0):
        0.2247355259061654
        0.2981547999074439
        0.23002471487530218
        0.15749698067082712
        0.009459903074000367
        0.8291698869058668
        0.1367646699608786
        0.22908912270217624
Random floating point numbers from normal distribution mean=42, standard deviation=5:
        35.23340522476584
        46.930543271537225
        42.257069766022894
        35.354253981998625
        41.3176988941606
        45.183924496995424
        44.739646992171515
        42.407759769057996
Certified random data:
c2 95 92 0e fa d4 5c   from 120 bits, with 66.8671875 bits of entropy
e8 78 3e 7f bd db fb   from 120 bits, with 66.84375 bits of entropy
a3 fd bf 61 9b 55 e7   from 120 bits, with 66.8515625 bits of entropy
04 52 51 5d b0 0e 7a   from 120 bits, with 66.8515625 bits of entropy
69 e0 f3 11 59 a5 54   from 120 bits, with 66.859375 bits of entropy
02 27 5e 1f 63 1d be   from 120 bits, with 66.875 bits of entropy
a9 58 da 63 01 b9 14   from 120 bits, with 66.8671875 bits of entropy
25 af 05 8b 6f 03 b7   from 120 bits, with 66.8515625 bits of entropy

Certified random data is provided in blocks which contain 64 bits of randomness each. Each block was generated from unconditioned data, the size of which is shown. The estimated entropy content of that unconditioned data is also shown. While the entropy is shown as being greater than 64, obviously the actual conditioned data cannot fit more than 64 bits of entropy into 64 bits of data. The entropy estimate is larger because the conditioning guarantees to provide at least (and therefore exactly) 64 bits of entropy in the 64 random bits. If there a fault arises in the entropy source, the reported number of bits will be less than 64 (in fact, almost certainly 0) which shows the randomness should be discarded. In contrast, fetching uncertified random bits during a fault condition will block until the fault is corrected - it will never return data which has an entropy estimate less than its size.

Running the C and C++ demos

Unpack the software into a convenient directory. In that directory run:

make
you should find that in the BUILT subdirectory you now have:

The qdremdemo program fetches 100KB of random data. Try it out like this:

qdremdemo 20.100.202.187 33399 demosrv-cert.pem cli-cert.pem cli-key.pem >qd.rnd
and you should find that the file qd.rnd now contains 1024000 bytes of random data.

The qdremdemo_ce demonstrates the certification and entropy values accompanying randomness. Run it like this:

qdremdemo_ce 20.100.202.187 33399 demosrv-cert.pem cli-cert.pem cli-key.pem
and it will fetch blocks of randomness and print their contents. Each line looks like this:
144     72.953125       8d 49 1b b0 e7 c6 81 cf
where the first number is the number of unconditioned bits that were used in producing this block, the second is the estimate of the amount of entropy in those bits, and the eight hex values are the 64 bits of randomness in this block. In unusual circumstances, if the randomness generator is unable to generate sufficient entropy in a reasonable time, the value for entropy is less than 64 and this block should not be used. When you get a stream of random data without metadata (as with the other demo programs) the stream does not contain any data from blocks like these, so may be delayed arbitrarily.

The qdremdemo_norm demonstrates generation of random values according to a specific probability distribution using the standard C++ distributions. Try it like this:

qdremdemo_norm 20.100.202.187 33399 demosrv-cert.pem cli-cert.pem cli-key.pem
and you should find it prints out 42 values from a Gaussian normal distribution which has mean of 42 and standard deviation of 5.

Running the python numpy demo

Unpack the software into a convenient directory. In that directory you now have:

The qdnumpydemo program uses the Quantum Dice randomness server as a randomness generator for numpy.

Note that it uses the python module randomgen which is you most likely need to install but which is not currently included in the standard Debian distribution (and hence derivatives such as Ubuntu), so the usual command of apt install python3-randomgen will not find and install it. You will need to install using pip install randomgen. Typically this would be done into a virtual environment:

$ python3 -m venv qdrand-env
$ source qdrand-env/bin/activate
(qdrand-env) $ pip install randomgen
(qdrand-env) $ python3 qdnumpydemo.py 20.100.202.187 33399 demosrv-cert.pem cli-cert.pem cli-key.pem
To run the demo use:
python3 qdnumpydemo.py 20.100.202.187 33399 demosrv-cert.pem cli-cert.pem cli-key.pem
and it should print something like this:
Randint_64: 3028800426629873715
5 values from QDRandom via UserBitGenerator: [ 2566153804708623171   367241064909403286 14845878088422313213
 10689817887016309455   642781941046069738]
normal distribution: [41.49551784 40.14690052 35.98635924 38.85922673 35.93685133 41.79434128
 42.73581742]
uniform distribution: [31.17760795 22.83976742  6.13916706 25.79482315  9.61263327 23.01004319
 29.38847962]
binomial: [2 4 3 5 6 6 3]

Using Quantum Dice randomness in your own code

Using Quantum Dice randomness in C code

Use qdremdemo_ce.c as a starting point. You need to include qdremrand.h and initialise the connection to the EaaS server with:

 QDREMRAND qdr;
 qdremrand(&qdr);
 if (qdremrand_connect(&qdr, rem_host, rem_port, peer_cert, my_cert, my_key)) {
        fprintf(stderr, "Cannot connect to QD remote randomness\n");
        return 1;
 }

then if you want metadata with your randomness, fetch it like this:

	struct qdrandom randbuf[16];
        ssize_t got = qdremrand_getrand_ce(&qdr, randbuf, ARRAY_SIZE(randbuf));
        if (got == -1) {
                fprintf(stderr, "qdremrand_getrand_ce() failed\nCannot get random data\n");
                return 1;
        }
or for just a stream of randomness, fetch it like this:
	unsigned char rands[16000];
        ssize_t got = qdremrand_getrand(&qdr, rands, sizeof(rands));
        if (got == -1) {
                fprintf(stderr, "qdremrand_getrand() failed\nCannot get random data\n");
                return 1;
        }

Using Quantum Dice randomness in C++ code

You can use the demo programs to see how you can use the randomness in your own code. In qdremdemo.cpp it initialises the connection to the EaaS server with:

 Qdremrand qdr;
 if (qdr.connect(rem_host, rem_port, peer_cert, my_cert, my_key)) {
        std::cerr << "Cannot connect to QD remote randomness\n";
        return 1;
 }
and gets blocks of random bytes with:
	unsigned char randbuf[64000];
        ssize_t got = qdr.getrand(randbuf, sizeof(randbuf));
        if (got == -1) {
                fprintf(stderr, "getrand() failed\nCannot get random data\n");
		...
while qdremdemo_norm.cpp sets up a distribution with:
 Qdremrand qdr;
 if (qdr.connect(rem_host, rem_port, peer_cert, my_cert, my_key)) {
        std::cerr << "Cannot connect to QD remote randomness\n";
        return 1;
 }
 Filerand<uint_fast32_t> qd_gen(&qdr);
 std::normal_distribution norm(42.0, 5.0);
and then fetches and prints each value with:
        std::cout << norm(qd_gen) << "\n";
You can get all the standard C++ randomness distributions this way.

Using Quantum Dice randomness in python code

The qdremrand.py file is the python module that you can import in your own code to access the server. For python's standard builtin randomness functions, use it like this:

import qdremrand

...
qrn = qdremrand.QDRemRand(host, int(port), srvcert, clicert, clikey)

and you can get all the standard randomness functionality from qrn.

Use with numpy

For use with numpy, instead of using:

npg = numpy.random.default_rng()
use
from randomgen import UserBitGenerator
import numpy
import qdremrand
...
qdr = qdremrand.QDRemRand(host, int(port), srvcert, clicert, clikey)
qd_ubg = UserBitGenerator(qdr.randint_64, 64, next_32=qdr.randint_32)
npg = numpy.random.Generator(qd_ubg)
and you can use npg as usual. One big difference is that parallelism is much simpler. You can create multiple connections to the Quantum Dice server and use them in parallel with no need to worry about using different seeds or skipping ahead to avoid duplicate random numbers.

Adding Quantum Dice randomness to the Linux /dev/random pool

The simplest way to add randomness to the Linux /dev/random pool is to fetch randomness into a file, qd.rnd (as done in the example of using qdremdemo above) and copy it in:

cat qd.rnd >/dev/random
however, this does not update the pool's estimate of its entropy. That can only be done with an ioctl(), and there is a handy utility provided in the demo package to do this. To use it, after you have built the C/C++ demo programs, run:
BUILT/linuxaddrand -s 1 <qd.rnd
The -s option is the safety factor which indicates how much entropy is in the data being written. For example, if you think that your data is 30% random, you specify -s 0.3 but for Quantum Dice randomness, since it is derived from truly random quantum processes and carefully conditioned, it should be pure randomness, so specify -s 1 . If you omit this option, it defaults to 0 so the effect is the same as merely writing the data to /dev/random. Note that this utility is supplied as a separate program for security. Updating the pool entropy estimate is a privileged operation, so it will have to be run as root, but fetching data from the EaaS server does not require any special privilege, so should not be done by root.