The TKey Secure Random Number Generator app allows a user and a client system to get high-quality random numbers from a source separate from the client. A unique feature of the app is that it can also sign the random data delivered, thus allowing the user to verify the integrity of the generator, the integrity of the data, and the origin of the data delivered. But a secure random number generator must also deliver high-quality random numbers. In this blog post, we will look at how the generator works and the measured quality. In a coming blog post will discuss the signing and verifying in more detail.
The TKey Secure Random Number Generator app is influenced by the Hash_DRBG random number generator specified by NIST in SP 800-90A. The Hash_DRBG is what NIST refers to as a deterministic random bit generator (DBRG), basically an algorithm that, given a seed state, will generate a sequence of numbers while updating its internal state. Outside of NIST, these types of algorithms are called pseudorandom number generators (PRNGs) and, for security-related use cases, cryptographically secure pseudo random number generators (CSPRNG).
An important aspect of a CSPRNG is that there is an internal, secret state that is used to generate the output. But observing the generated output does not aid an attacker in being able to guess previous or future outputs. The state may also be reseeded to add new entropy (i.e., random noise collected from a physical source) to make it harder for an attacker to guess the internal state.
The Hash_DRBG is built around a cryptographically secure hash function, for example SHA-256. The internal state is hashed. Parts of the resulting digest are presented as output. The digest, combined with internal counters, is used to update the internal state.
The NIST Hash_DRBG standard is quite complex, with requirements on functions to instantiate or remove a generator, mechanisms to set and check security levels, etc. For the TKey application, these functions do not really make sense, and we chose not to implement all of the required functionality according to the standard. This is why we say that the generator is influenced by, not an implementation of, the NIST Hash_DRBG.
The app uses the BLAKE2s hash function. BLAKE2s is available in the TKey firmware for applications to use. BLAKE2s is also faster than SHA-256. The internal state is a complete, 512-bit BLAKE2s block. The digest generated by BLAKE2s is 256 bits and of these, 128 bits (16 bytes) are presented to the client as output.
The internal state as well as support counters, etc. are defined in a rng_ctx (ctx as in context) struct that can be found in rng.h. The structure is as follows:
// state context
typedef struct {
uint32_t state_ctr_lsb;
uint32_t state_ctr_msb;
uint32_t reseed_ctr;
uint32_t state[16];
uint32_t digest[8];
} rng_ctx;
Going through the context structure will help explain how the context is created, updated, and used during random data generation.
The state_ctr_lsb and state_ctr_msb together form a 64-bit, non-saturating counter. This counter is randomly initialized when the TKey application is started using the TKey True Random Number Generator (TRNG) entropy source. The counter is monotonically increased each time a hash digest is generated. The counter values are mixed into two of the state words updated with the digest. This prevents the hash state from being static between two hash operations, even if the digest generated is the same.
The reseed_ctr keeps track of the number of hash operations performed and, thus, when it is time to reseed the state. By default, reseed happens every 1000 hash operations. That is, every 16 kiByte of generated data will be based on new entropy. The reseed frequency is defined at compile time to not allow an attacker to change the frequency through a command.
The state array is the “message” being hashed to generate the digest. The state is divided into two parts: The lower eight 32-bit words are updated every time a digest has been calculated. The upper eight 32-bit words contain the entropy collected during the last reseed. When updating the state, the latest digest is moved into the lower eight words of the state. Additionally, the counter is updated, and its 64-bit value is added to word 14 and 15, meaning that the entropy part will always change between hash operations.
When the TKey app has been loaded, the lower eight words of the state are initialized with the CDI calculated using the UDS and any User Supplied Secret (USS) by the firmware when the device app was loaded onto the TKey.
The digest is the latest digest generated and is stored until all 16 bytes have been provided to the client, and a new digest will then be generated.
We tested the generator by extracting about 1 GByte of data and then using two well-known programs.
ENT is a tool that is fast and easy to use. It does not provide a comprehensive test of random data, but its set of tests will detect a really broken generator. Thus, it is a good initial test. The test results from ENT:
Entropy = 8.000000 bits per byte.
Optimum compression would reduce the size
of this 1135320598 byte file by 0 percent.
Chi square distribution for 1135320598 samples is 250.82, and randomly
would exceed this value 56.22 percent of the times.
Arithmetic mean value of data bytes is 127.5021 (127.5 = random).
Monte Carlo value for Pi is 3.141601316 (error 0.00 percent).
Serial correlation coefficient is -0.000001 (totally uncorrelated = 0.0).
The ENT results indicate no obvious patterns that can be compressed, no bias, and a distribution close to what is expected for a uniform random number source.
A much more comprehensive test suite is provided by the tool PractRand. Compared to tools such as Dieharder, PractRand is harder to misuse. But similarly to Dieharder, it needs a lot of data to run its battery of tests. The test results from PractRand:
rng=RNG_stdin, seed=unknown
length= 1 gigabyte (2^30 bytes), time= 8.5 seconds
Test Name Raw Processed Evaluation
BCFN(2+0,13-1,T) R= +2.6 p = 0.141 normal
BCFN(2+1,13-1,T) R= +2.1 p = 0.193 normal
BCFN(2+2,13-1,T) R= -2.2 p = 0.811 normal
BCFN(2+3,13-1,T) R= +2.7 p = 0.133 normal
BCFN(2+4,13-2,T) R= -5.0 p = 0.983 normal
BCFN(2+5,13-3,T) R= +3.8 p = 0.065 normal
BCFN(2+6,13-3,T) R= +2.9 p = 0.120 normal
BCFN(2+7,13-4,T) R= -1.4 p = 0.706 normal
BCFN(2+8,13-5,T) R= -0.5 p = 0.552 normal
BCFN(2+9,13-5,T) R= +0.8 p = 0.350 normal
BCFN(2+10,13-6,T) R= +3.7 p = 0.071 normal
BCFN(2+11,13-6,T) R= -2.1 p = 0.806 normal
BCFN(2+12,13-7,T) R= -1.3 p = 0.683 normal
BCFN(2+13,13-8,T) R= +3.4 p = 0.084 normal
BCFN(2+14,13-8,T) R= +1.6 p = 0.208 normal
BCFN(2+15,13-9,T) R= +0.1 p = 0.388 normal
BCFN(2+16,13-9,T) R= -0.5 p = 0.509 normal
DC6-9x1Bytes-1 R= -0.8 p = 0.753 normal
Gap-16:A R= +2.3 p = 0.096 normal
Gap-16:B R= +0.5 p = 0.366 normal
FPF-14+6/16:(0,14-0) R= -1.1 p = 0.782 normal
FPF-14+6/16:(1,14-0) R= +1.4 p = 0.158 normal
FPF-14+6/16:(2,14-0) R= +0.0 p = 0.489 normal
FPF-14+6/16:(3,14-0) R= -0.1 p = 0.524 normal
FPF-14+6/16:(4,14-0) R= +0.7 p = 0.323 normal
FPF-14+6/16:(5,14-0) R= +1.2 p = 0.210 normal
FPF-14+6/16:(6,14-1) R= -0.1 p = 0.546 normal
FPF-14+6/16:(7,14-2) R= -3.6 p =1-4.4e-3 normal
FPF-14+6/16:(8,14-2) R= -0.3 p = 0.573 normal
FPF-14+6/16:(9,14-3) R= -0.2 p = 0.568 normal
FPF-14+6/16:(10,14-4) R= +2.0 p = 0.085 normal
FPF-14+6/16:(11,14-5) R= -1.6 p = 0.871 normal
FPF-14+6/16:(12,14-5) R= -1.1 p = 0.778 normal
FPF-14+6/16:(13,14-6) R= -0.9 p = 0.739 normal
FPF-14+6/16:(14,14-7) R= -1.3 p = 0.830 normal
FPF-14+6/16:(15,14-8) R= +0.0 p = 0.475 normal
FPF-14+6/16:(16,14-8) R= -2.1 p = 0.946 normal
FPF-14+6/16:(17,14-9) R= -0.8 p = 0.701 normal
FPF-14+6/16:(18,14-10) R= +1.1 p = 0.212 normal
FPF-14+6/16:(19,14-11) R= -0.8 p = 0.679 normal
FPF-14+6/16:(20,14-11) R= +0.6 p = 0.295 normal
FPF-14+6/16:all R= -0.3 p = 0.588 normal
FPF-14+6/16:cross R= +0.0 p = 0.446 normal
BRank(12):128(8) R= -0.3 p~= 0.500 normal
BRank(12):256(4) R= -0.2 p~= 0.500 normal
BRank(12):384(1) R= -0.7 p~= 0.689 normal
BRank(12):512(4) R= -0.2 p~= 0.500 normal
BRank(12):768(1) R= +1.8 p~= 0.146 normal
BRank(12):1K(2) R= -0.2 p~= 0.554 normal
BRank(12):1536(1) R= -0.7 p~= 0.689 normal
BRank(12):2K(2) R= +0.6 p~= 0.322 normal
BRank(12):3K(1) R= +1.8 p~= 0.146 normal
mod3n(5):(0,9-0) R= +4.1 p = 0.023 normal
mod3n(5):(1,9-0) R= -1.5 p = 0.771 normal
mod3n(5):(2,9-1) R= -5.8 p =1-1.6e-3 normalish
mod3n(5):(3,9-1) R= -1.9 p = 0.834 normal
mod3n(5):(4,9-2) R= -2.9 p = 0.932 normal
mod3n(5):(5,9-2) R= -3.2 p = 0.947 normal
mod3n(5):(6,9-3) R= +3.1 p = 0.064 normal
mod3n(5):(7,9-3) R= +0.2 p = 0.459 normal
mod3n(5):(8,9-4) R= +0.1 p = 0.452 normal
mod3n(5):(9,9-4) R= +0.2 p = 0.441 normal
mod3n(5):(10,9-5) R= +2.0 p = 0.146 normal
mod3n(5):(11,9-5) R= -0.9 p = 0.646 normal
mod3n(5):(12,9-6) R= +3.0 p = 0.070 normal
mod3n(5):(13,9-6) R= +5.6 p = 9.3e-3 normal
mod3n(5):(14,9-6) R= -1.0 p = 0.668 normal
mod3n(5):(15,9-6) R= -1.7 p = 0.828 normal
TMFn(2+0):wl R= -0.1 p~= 0.5 normal
TMFn(2+1):wl R= -3.6 p~= 0.9 normal
TMFn(2+2):wl R= +0.0 p~= 0.5 normal
TMFn(2+3):wl R= +1.2 p~= 0.3 normal
TMFn(2+4):wl R= +0.7 p~= 0.4 normal
TMFn(2+5):wl R= +0.4 p~= 0.4 normal
[Low1/8]BCFN(2+0,13-3,T) R= +2.1 p = 0.193 normal
[Low1/8]BCFN(2+1,13-3,T) R= +1.0 p = 0.329 normal
[Low1/8]BCFN(2+2,13-3,T) R= -3.6 p = 0.936 normal
[Low1/8]BCFN(2+3,13-3,T) R= -2.5 p = 0.848 normal
[Low1/8]BCFN(2+4,13-4,T) R= +6.2 p = 0.011 normal
[Low1/8]BCFN(2+5,13-5,T) R= -0.6 p = 0.569 normal
[Low1/8]BCFN(2+6,13-5,T) R= +2.3 p = 0.167 normal
[Low1/8]BCFN(2+7,13-6,T) R= +3.3 p = 0.095 normal
[Low1/8]BCFN(2+8,13-6,T) R= -0.3 p = 0.506 normal
[Low1/8]BCFN(2+9,13-7,T) R= +0.3 p = 0.406 normal
[Low1/8]BCFN(2+10,13-8,T) R= +4.8 p = 0.039 normal
[Low1/8]BCFN(2+11,13-8,T) R= -0.3 p = 0.482 normal
[Low1/8]BCFN(2+12,13-9,T) R= +2.3 p = 0.135 normal
[Low1/8]BCFN(2+13,13-9,T) R= +1.1 p = 0.253 normal
[Low1/8]DC6-9x1Bytes-1 R= -1.1 p = 0.831 normal
[Low1/8]Gap-16:A R= +2.3 p = 0.105 normal
[Low1/8]Gap-16:B R= +2.4 p = 0.048 normal
[Low1/8]FPF-14+6/16:(0,14-0) R= +2.1 p = 0.070 normal
[Low1/8]FPF-14+6/16:(1,14-0) R= -0.7 p = 0.682 normal
[Low1/8]FPF-14+6/16:(2,14-0) R= -0.5 p = 0.634 normal
[Low1/8]FPF-14+6/16:(3,14-1) R= -0.5 p = 0.637 normal
[Low1/8]FPF-14+6/16:(4,14-2) R= +0.4 p = 0.389 normal
[Low1/8]FPF-14+6/16:(5,14-2) R= -0.0 p = 0.509 normal
[Low1/8]FPF-14+6/16:(6,14-3) R= +1.6 p = 0.131 normal [Low1/8]FPF-14+6/16:(7,14-4) R= +1.3 p = 0.178 normal [Low1/8]FPF-14+6/16:(8,14-5) R= -2.0 p = 0.923 normal [Low1/8]FPF-14+6/16:(9,14-5) R= -0.4 p = 0.620 normal [Low1/8]FPF-14+6/16:(10,14-6) R= +2.1 p = 0.073 normal [Low1/8]FPF-14+6/16:(11,14-7) R= +2.9 p = 0.029 normal [Low1/8]FPF-14+6/16:(12,14-8) R= -1.6 p = 0.873 normal [Low1/8]FPF-14+6/16:(13,14-8) R= +0.8 p = 0.267 normal [Low1/8]FPF-14+6/16:(14,14-9) R= -0.3 p = 0.544 normal [Low1/8]FPF-14+6/16:(15,14-10) R= -1.5 p = 0.866 normal [Low1/8]FPF-14+6/16:(16,14-11) R= -1.3 p = 0.841 normal [Low1/8]FPF-14+6/16:(17,14-11) R= +3.9 p = 0.016 normal [Low1/8]FPF-14+6/16:all R= +0.8 p = 0.311 normal [Low1/8]FPF-14+6/16:cross R= +0.4 p = 0.322 normal
[Low1/8]BRank(12):128(4) R= -0.8 p~= 0.670 normal
[Low1/8]BRank(12):256(4) R= -1.4 p~= 0.890 normal
[Low1/8]BRank(12):384(1) R= -0.7 p~= 0.689 normal
[Low1/8]BRank(12):512(2) R= -1.0 p~= 0.744 normal
[Low1/8]BRank(12):768(1) R= -0.7 p~= 0.689 normal
[Low1/8]BRank(12):1K(2) R= +0.6 p~= 0.322 normal
[Low1/8]BRank(12):1536(1) R= +1.8 p~= 0.146 normal
[Low1/8]mod3n(5):(0,9-1) R= +2.1 p = 0.145 normal
[Low1/8]mod3n(5):(1,9-2) R= +4.2 p = 0.021 normal
[Low1/8]mod3n(5):(2,9-2) R= +3.7 p = 0.035 normal
[Low1/8]mod3n(5):(3,9-3) R= +2.6 p = 0.100 normal
[Low1/8]mod3n(5):(4,9-3) R= +2.1 p = 0.151 normal
[Low1/8]mod3n(5):(5,9-4) R= -1.5 p = 0.767 normal
[Low1/8]mod3n(5):(6,9-4) R= -1.3 p = 0.732 normal
[Low1/8]mod3n(5):(7,9-5) R= +2.2 p = 0.129 normal
[Low1/8]mod3n(5):(8,9-5) R= -2.1 p = 0.866 normal
[Low1/8]mod3n(5):(9,9-6) R= +0.2 p = 0.405 normal
[Low1/8]mod3n(5):(10,9-6) R= -0.8 p = 0.633 normal
[Low1/8]mod3n(5):(11,9-6) R= -0.5 p = 0.563 normal
[Low1/8]mod3n(5):(12,9-6) R= +0.5 p = 0.352 normal
[Low1/8]mod3n(5):(13,9-6) R= +2.6 p = 0.092 normal
[Low1/8]TMFn(2+0):wl R= -1.1 p~= 0.7 normal
[Low1/8]TMFn(2+1):wl R= +1.4 p~= 0.3 normal
[Low1/8]TMFn(2+2):wl R= +1.9 p~= 0.3 normal
[Low4/32]BCFN(2+0,13-3,T) R= +2.6 p = 0.142 normal
[Low4/32]BCFN(2+1,13-3,T) R= +0.9 p = 0.344 normal
[Low4/32]BCFN(2+2,13-3,T) R= +2.5 p = 0.151 normal
[Low4/32]BCFN(2+3,13-3,T) R= +1.2 p = 0.297 normal
[Low4/32]BCFN(2+4,13-4,T) R= +0.2 p = 0.449 normal
[Low4/32]BCFN(2+5,13-5,T) R= -0.1 p = 0.491 normal
[Low4/32]BCFN(2+6,13-5,T) R= +3.9 p = 0.064 normal
[Low4/32]BCFN(2+7,13-6,T) R= +9.5 p = 1.1e-3 normal
[Low4/32]BCFN(2+8,13-6,T) R= -3.9 p = 0.969 normal
[Low4/32]BCFN(2+9,13-7,T) R= +5.3 p = 0.028 normal
[Low4/32]BCFN(2+10,13-8,T) R= -0.8 p = 0.591 normal
[Low4/32]BCFN(2+11,13-8,T) R= -1.6 p = 0.733 normal
[Low4/32]BCFN(2+12,13-9,T) R= -2.4 p = 0.910 normal
[Low4/32]BCFN(2+13,13-9,T) R= -2.3 p = 0.893 normal
[Low4/32]DC6-9x1Bytes-1 R= +1.4 p = 0.362 normal
[Low4/32]Gap-16:A R= +0.8 p = 0.420 normal
[Low4/32]Gap-16:B R= +0.8 p = 0.283 normal
[Low4/32]FPF-14+6/16:(0,14-0) R= +0.0 p = 0.492 normal
[Low4/32]FPF-14+6/16:(1,14-0) R= +0.5 p = 0.358 normal
[Low4/32]FPF-14+6/16:(2,14-0) R= +2.8 p = 0.027 normal
[Low4/32]FPF-14+6/16:(3,14-1) R= +2.0 p = 0.078 normal
[Low4/32]FPF-14+6/16:(4,14-2) R= -0.1 p = 0.532 normal
[Low4/32]FPF-14+6/16:(5,14-2) R= -0.9 p = 0.743 normal
[Low4/32]FPF-14+6/16:(6,14-3) R= -1.3 p = 0.830 normal
[Low4/32]FPF-14+6/16:(7,14-4) R= -0.1 p = 0.529 normal
[Low4/32]FPF-14+6/16:(8,14-5) R= -0.8 p = 0.715 normal
[Low4/32]FPF-14+6/16:(9,14-5) R= +1.1 p = 0.210 normal
[Low4/32]FPF-14+6/16:(10,14-6) R= +1.3 p = 0.178 normal
[Low4/32]FPF-14+6/16:(11,14-7) R= -0.9 p = 0.730 normal
[Low4/32]FPF-14+6/16:(12,14-8) R= -2.0 p = 0.930 normal
[Low4/32]FPF-14+6/16:(13,14-8) R= -1.6 p = 0.885 normal
[Low4/32]FPF-14+6/16:(14,14-9) R= +1.7 p = 0.126 normal
[Low4/32]FPF-14+6/16:(15,14-10) R= -1.2 p = 0.798 normal
[Low4/32]FPF-14+6/16:(16,14-11) R= +0.3 p = 0.362 normal
[Low4/32]FPF-14+6/16:(17,14-11) R= +2.9 p = 0.039 normal
[Low4/32]FPF-14+6/16:all R= +1.8 p = 0.118 normal
[Low4/32]FPF-14+6/16:cross R= -0.1 p = 0.500 normal
[Low4/32]BRank(12):128(4) R= -0.8 p~= 0.670 normal
[Low4/32]BRank(12):256(4) R= -0.1 p~= 0.490 normal
[Low4/32]BRank(12):384(1) R= -0.7 p~= 0.689 normal
[Low4/32]BRank(12):512(2) R= +0.8 p~= 0.293 normal
[Low4/32]BRank(12):768(1) R= +0.4 p~= 0.366 normal
[Low4/32]BRank(12):1K(2) R= -1.0 p~= 0.744 normal
[Low4/32]BRank(12):1536(1) R= +1.8 p~= 0.146 normal
[Low4/32]mod3n(5):(0,9-1) R= +3.7 p = 0.032 normal
[Low4/32]mod3n(5):(1,9-2) R= +3.4 p = 0.049 normal
[Low4/32]mod3n(5):(2,9-2) R= -3.1 p = 0.946 normal
[Low4/32]mod3n(5):(3,9-3) R= -0.4 p = 0.575 normal
[Low4/32]mod3n(5):(4,9-3) R= +3.5 p = 0.043 normal
[Low4/32]mod3n(5):(5,9-4) R= -0.9 p = 0.656 normal
[Low4/32]mod3n(5):(6,9-4) R= -1.2 p = 0.725 normal
[Low4/32]mod3n(5):(7,9-5) R= +1.5 p = 0.213 normal
[Low4/32]mod3n(5):(8,9-5) R= -2.4 p = 0.905 normal
[Low4/32]mod3n(5):(9,9-6) R= -1.0 p = 0.676 normal
[Low4/32]mod3n(5):(10,9-6) R= +1.2 p = 0.232 normal
[Low4/32]mod3n(5):(11,9-6) R= +1.6 p = 0.180 normal
[Low4/32]mod3n(5):(12,9-6) R= -1.8 p = 0.836 normal
[Low4/32]mod3n(5):(13,9-6) R= +0.3 p = 0.374 normal
[Low4/32]TMFn(2+0):wl R= +1.0 p~= 0.4 normal
[Low4/32]TMFn(2+1):wl R= -1.9 p~= 0.7 normal
[Low4/32]TMFn(2+2):wl R= +0.8 p~= 0.4 normal
[Low1/32]BCFN(2+0,13-4,T) R= +0.1 p = 0.462 normal
[Low1/32]BCFN(2+1,13-4,T) R= +1.7 p = 0.230 normal
[Low1/32]BCFN(2+2,13-5,T) R= +0.3 p = 0.422 normal
[Low1/32]BCFN(2+3,13-5,T) R= -3.8 p = 0.957 normal
[Low1/32]BCFN(2+4,13-5,T) R= +5.7 p = 0.018 normal
[Low1/32]BCFN(2+5,13-6,T) R= -1.0 p = 0.641 normal
[Low1/32]BCFN(2+6,13-6,T) R= -4.2 p = 0.979 normal
[Low1/32]BCFN(2+7,13-7,T) R= -1.5 p = 0.711 normal
[Low1/32]BCFN(2+8,13-8,T) R= -0.1 p = 0.444 normal
[Low1/32]BCFN(2+9,13-8,T) R= +0.2 p = 0.407 normal
[Low1/32]BCFN(2+10,13-9,T) R= +2.7 p = 0.111 normal
[Low1/32]BCFN(2+11,13-9,T) R= -2.6 p = 0.933 normal
[Low1/32]DC6-9x1Bytes-1 R= +2.5 p = 0.182 normal
[Low1/32]FPF-14+6/16:(0,14-0) R= +0.1 p = 0.476 normal
[Low1/32]FPF-14+6/16:(1,14-1) R= -1.8 p = 0.908 normal
[Low1/32]FPF-14+6/16:(2,14-2) R= -0.1 p = 0.528 normal
[Low1/32]FPF-14+6/16:(3,14-2) R= +1.1 p = 0.227 normal
[Low1/32]FPF-14+6/16:(4,14-3) R= -0.0 p = 0.507 normal
[Low1/32]FPF-14+6/16:(5,14-4) R= +1.1 p = 0.212 normal
[Low1/32]FPF-14+6/16:(6,14-5) R= +1.1 p = 0.223 normal
[Low1/32]FPF-14+6/16:(7,14-5) R= -0.3 p = 0.594 normal
[Low1/32]FPF-14+6/16:(8,14-6) R= -1.8 p = 0.897 normal
[Low1/32]FPF-14+6/16:(9,14-7) R= -0.1 p = 0.512 normal
[Low1/32]FPF-14+6/16:(10,14-8) R= -0.3 p = 0.565 normal
[Low1/32]FPF-14+6/16:(11,14-8) R= -0.9 p = 0.727 normal
[Low1/32]FPF-14+6/16:(12,14-9) R= -0.6 p = 0.648 normal
[Low1/32]FPF-14+6/16:(13,14-10) R= -0.0 p = 0.455 normal
[Low1/32]FPF-14+6/16:(14,14-11) R= +5.5 p = 3.5e-3 normal
[Low1/32]FPF-14+6/16:(15,14-11) R= -0.1 p = 0.471 normal
[Low1/32]FPF-14+6/16:all R= -0.4 p = 0.627 normal
[Low1/32]FPF-14+6/16:cross R= -0.1 p = 0.502 normal
[Low1/32]BRank(12):128(4) R= +0.4 p~= 0.340 normal
[Low1/32]BRank(12):256(2) R= -0.2 p~= 0.554 normal
[Low1/32]BRank(12):384(1) R= -0.7 p~= 0.689 normal
[Low1/32]BRank(12):512(2) R= +0.6 p~= 0.322 normal
[Low1/32]BRank(12):768(1) R= +1.8 p~= 0.146 normal
[Low1/32]BRank(12):1K(1) R= +0.4 p~= 0.366 normal
[Low1/32]mod3n(5):(0,9-2) R= -0.7 p = 0.626 normal
[Low1/32]mod3n(5):(1,9-3) R= +1.6 p = 0.206 normal
[Low1/32]mod3n(5):(2,9-3) R= +2.8 p = 0.084 normal
[Low1/32]mod3n(5):(3,9-4) R= -0.2 p = 0.530 normal
[Low1/32]mod3n(5):(4,9-4) R= +3.5 p = 0.049 normal
[Low1/32]mod3n(5):(5,9-5) R= -3.4 p = 0.977 normal
[Low1/32]mod3n(5):(6,9-5) R= -0.3 p = 0.519 normal
[Low1/32]mod3n(5):(7,9-6) R= +1.0 p = 0.257 normal
[Low1/32]mod3n(5):(8,9-6) R= +1.6 p = 0.176 normal
[Low1/32]mod3n(5):(9,9-6) R= +3.3 p = 0.057 normal
[Low1/32]mod3n(5):(10,9-6) R= +4.3 p = 0.026 normal
[Low1/32]mod3n(5):(11,9-6) R= +2.0 p = 0.136 normal
[Low1/32]TMFn(2+0):wl R= -0.6 p~= 0.6 normal
PractRand performs a lot of tests, but none of the tests performed by PractRand failed. This result indicates that the TKey app can produce random numbers with a quality on par with that expected from a working random number generator capable of generating data that can be used for security-related use cases.
The TKey random number generator app is a high-quality generator based around the BLAKE2s hash function with a state updated using the TKey internal true random number source. The app can be used in systems that need access to cryptographically strong random numbers. And since the app is also able to sign the data (which we will cover in another blog post), it can be trusted to come from the TKey and the app described here.
Cover image: Gordon Johnson