As unequivocal proof of the ease with which you can build a high quality, cryptographic strength entropy source, here is one we built earlier on Granny’s wooden breadboard:-

It is a Chekhov circuit, which is the simplest possible entropy generating circuit. So simple in fact that we built it on a wooden board (literally a breadboard). And even used real steel nails. The circuit is named after Anton Chekhov, who said *“Only entropy comes easy”*. Such wisdom! Essentially, it’s a common BZX 27 volt Zener diode plus 680 kΩ current limiting resistor thus:-

The thermo-nuclear shielding (box made of cryptographic plastic) is necessary to protect the Zener from all light as the junction is within a transparent glass encapsulation. Incident light disrupts the electron avalanche effect and reduces the entropy signal. Nominal reverse current = 18uA as the battery is actually ~39V. 36V is only the nominal value of 4 no. 9V batteries. Frankly, the diode current is somewhat higher, probably nearer 30uA as we use a direct x1 BNC cable. That’s about 110 trillion electrons tumbling through the junction every second. The combined 1MΩ scope impedance and limiting resistor parallel out at about 404 kΩ. This resistance acts with the junction capacitance to marginally distort the expected characteristic log normal signal distribution.

It’s a true quantum entropy source for the reasons explained previously in relation to the Avalanche effect within Zener diodes. It really doesn’t have to involve lasers or vacuum point energy to be quantum based. Although stale bread crumbs, semi-dried tomato juice and rotting pieces of salami can have a deleterious effect on circuit impedances and thus entropy rates. Lunches aside, our Chekhov circuit produces a mean unamplified entropy signal of 1.93Vpp under standard sampling.

The above ~1.9Vpp signal is readily manipulated by keen individuals, and guaranteed to be caused by the Avalanche effect rather than some unspecified consequence of huge amplifier gain/power supply noise. And readily extracted from.

NIST and at least one popular cryptography forum seem to rigorously promote the diametrically opposite view, repeating over and over the futility of DIY constructions. Why? The proof is on the chopping board. Just turn it on…

Then stick the entire thing up an Arduino. Sampling was as: `= 127 + analogRead(portNo) - analogRead(portNo)`

to only use the lower 8 bits of the Arduino’s ADC. This decreases sample storage space, and increases the entropy transfer rate off the Arduino. Bear in mind that this is only an entropy source, not a complete TRNG. Thus we are not looking for uniform output distributions at this stage. We’ll take what we can get. And what we got is available in the ‘Related files’ section below, including raw samples from an oscilloscope and an Arduino Uno, and some Python3 categorisation and utility scripts.

One of the fundamental paradigms of this site is that you don’t trust no one, and certainly not an obscure REALLYREALLYRANDOM.COM. The raw data is supplied for you to analyse yourselves, and to reach your own independent conclusions. But don’t believe the data either. Build this source, gather your own data and see what you think. Simply treat our data, code and formulae as hypothetical possibilities of what might be in a utopian cryptographic future. Like serving suggestions on tinned food.

First impression: Just as in US Supreme Court Justice Stewart’s definition, The Casablanca Test: “I know it [obscenity/pornography] when I see it,” we can tell that the sampled signal contains a good rate of entropy by seeing a visual representation. The following 400 pixel x 400 pixel image is a direct 1:1 greyscale view on the sampled data bytes. No recognizable patterns exist at either the micro or macro scales.

If you view the signal in the probability domain as above, we see a close similarity to the signal from the Zenerglass, a device built and sampled on similar principles. We characterize the histogram as a shifted bathtub distribution, typical of double samples with an offset. Sample autocorrelation is less than 0.0035, suggesting that they may be IID. We confirm this with an IID permutation test at the NIST standard 0.001 level. The maximum shuffled compression ratio was 1.00044. The pairwise sampling has proven sufficient to nullify any correlations.

The above permuted compressions test is our proprietary IID test, which is safely passed. Our tests are likewise confirmed by the following SP 800-90B IID test output:-

```
$ ./ea_iid -v -i -a /tmp/breadboard.bin 8
Opening file: '/tmp/breadboard.bin'
Loaded 1200000 samples of 256 distinct 8-bit-wide symbols
Number of Binary samples: 9600000
Calculating baseline statistics...
Raw Mean: 126.980571
Median: 127.000000
Binary: false
Literal MCV Estimate: mode = 21451, p-hat = 0.017875833333333334, p_u = 0.018187394258475383
Bitstring MCV Estimate: mode = 4806186, p-hat = 0.50064437500000003, p_u = 0.50106004734293053
H_original: 5.780917
H_bitstring: 0.996945
min(H_original, 8 X H_bitstring): 5.780917
Chi square independence
score = 25573.684818
degrees of freedom = 25490
p-value = 0.354506
Chi square goodness of fit
score = 2168.182062
degrees of freedom = 2088
p-value = 0.108316
** Passed chi square tests
LiteralLongest Repeated Substring results
P_col: 0.00945183
Length of LRS: 6
Pr(X >= 1): 0.40151
** Passed length of longest repeated substring test
Beginning initial tests...
Initial test results
excursion: 45579.9
numDirectionalRuns: 799801
lenDirectionalRuns: 9
numIncreasesDecreases: 605614
numRunsMedian: 600013
lenRunsMedian: 19
avgCollision: 12.7425
maxCollision: 50
periodicity(1): 11411
periodicity(2): 11493
periodicity(8): 11263
periodicity(16): 11495
periodicity(32): 11265
covariance(1): 1.93506e+10
covariance(2): 1.93509e+10
covariance(8): 1.9349e+10
covariance(16): 1.93477e+10
covariance(32): 1.935e+10
compression: 1.13442e+06
Beginning permutation tests... these may take some time
Permutation Test (core 02): 0): tests passed0 tests passed
Permutation Test (core 5): 0 tests passed
1): 0 tests passed
4): 0 tests passed
Permutation Test (core 3): 0 tests passed
Permutation Test (core 2): 0 tests passed
Permutation Test (core 5): 0 tests passed
Permutation Test (core 1): 0 tests passed
Permutation Test (core 0): 0 tests passed
Permutation Test (core 4): 0 tests passed
Permutation Test (core 3): 0 tests passed
Permutation Test (core 2): 0 tests passed
Permutation Test (core 5): 0 tests passed
Permutation Test (core 1): 0 tests passed
Permutation Test (core 0): 0 tests passed
Permutation Test (core 4): 0 tests passed
Permutation Test (core 3): 1 tests passed
Permutati...
...snip...
...ts passed
Permutation Test (core 0): 18 tests passed
Permutation Test (core 3): 18 tests passed
Permutation Test (core 4): 18 tests passed
Permutation Test (core 2): 18 tests passed
Permutation Test (core 5): 18 tests passed
Permutation Test (core 1): 18 tests passed
Permutation Test (core 0): 18 tests passed
Permutation Test (core 3): 18 tests passed
statistic C[i][0] C[i][1] C[i][2]
----------------------------------------------------
excursion 6 0 45
numDirectionalRuns 18 1 5
lenDirectionalRuns 2 4 6
numIncreasesDecreases 7 0 6
numRunsMedian 6 0 12
lenRunsMedian 12 5 1
avgCollision 6 0 7
maxCollision 4 2 8
periodicity(1) 6 0 32
periodicity(2) 6 0 67
periodicity(8) 14 0 6
periodicity(16) 6 0 55
periodicity(32) 7 0 6
covariance(1) 6 0 127
covariance(2) 6 0 69
covariance(8) 6 0 16
covariance(16) 8 0 6
covariance(32) 6 0 16
compression 6 0 540
(* denotes failed test)
** Passed IID permutation tests
```

We can then simply move onto an `ent`

test to find Pmax and thus the min.entropy ($H_\infty$) rate:-

```
$ ent -c /tmp/samples-10ksa.bin
Value Char Occurrences Fraction
0 4 0.000003
1 8 0.000007
2 7 0.000006
3 6 0.000005
4 15 0.000013
5 13 0.000011
6 18 0.000015
7 15 0.000013
8 23 0.000019
9 24 0.000020
10 19 0.000016
11 32 0.000027
12 30 0.000025
13 35 0.000029
14 38...
...snip...
...0.015081
122 z 18950 0.015792
123 { 19824 0.016520
124 | 20431 0.017026
125 } 21012 0.017510
126 ~ 21168 0.017640
127 21370 0.017808
128 21451 0.017876 ***** Pmax(Px = i)
129 21357 0.017798
130 20407 0.017006
131 19810 0.016508
132 18839 0.015699
133 18112 0.015093
134 16965 0.014138
135 16346 0.013622
136...
...snip...
...21 0.000017
247 � 18 0.000015
248 � 5 0.000004
249 � 11 0.000009
250 � 14 0.000012
251 � 8 0.000007
252 � 9 0.000008
253 � 6 0.000005
254 � 4 0.000003
255 � 12 0.000010
Total: 1200000 1.000000
Entropy = 7.046544 bits per byte.
```

A `cmix`

compressive entropy measurement produces a cross entropy of 7.056 bits/byte (double sample), which is within 0.13% of the above theoretical Shannon entropy under an IID assumption. Based on a Pmax of 0.017876 and confirmation of the data as IID, we can say that native $H_\infty$ of this breadboard source is **5.8 bits/byte (double sample)**. That’s an internal Arduino entropy generation rate of **~26kbps** (114,692us for 512 double samples) under standard sampling.

Randomness extraction and off loading from the Arduino board will of course lower this figure considerably. So what can we do with this..?

Cryptographic objective | Rate |
---|---|

Our bang for buck | 18.9 bps/g |

We create a single 256 bit key/IV | < 0.1s |

We rotate 256 bit keys | 25/s |

We fill 100 larger sized Tweets | 35s |

We create a 1MB one time pad | 20min. |

Speed of Fourmilab’s HotBits | 800bps |

Speed of NIST’s Randomness Beacon | 8.5bps |

Speed of Arduino Entropy Library | 64bps |

For the above comparisons table, we have assumed an $n \over m$ relationship of 2 across a generic $\text{Ext}: \{0,1\}^n \to \{0,1\}^m$ randomness extractor, followed by a further factor of safety of 2. **Final on-board cryptographic TRNG rate = 6,500bps** under standard sampling.

All that’s necessary is a Zener diode, resistor, batteries and a working hammer. Not too shoddy .