Generating random numbers from thread timing in C++ I have the following code blocks that generate apparently random numbers by using thread timing variations.

I am looking for a general code review, and a specific focus on whether the results are "true random numbers".

For computers with more than two CPUs

#include&lt;chrono&gt;
#include&lt;iostream&gt;
#include&lt;thread&gt;
using namespace std;

#define Mili 7
#define Base 7
#define Thrs 2

typedef unsigned char      Num;
typedef unsigned long long Out;

volatile Out out,tmp;

void inline thr(Num const num){
 while(true)
  out=out*Base+tmp,tmp=tmp*Base+num;
}

int main(){
 thread ths[Thrs];
 for(Num i=0;i&lt;Thrs;++i)
  ths[i]=thread(thr,i);
 this_thread::sleep_for(chrono::milliseconds(Mili));
 while(true)
  cout.write((char*)&amp;out,sizeof(out));
}


For computers with two CPUs

#include&lt;iostream&gt;
using namespace std;

#define Base 7
#define Iter 53

typedef unsigned char      Num;
typedef unsigned long long Out;

volatile Out out,tmp;

int main(){
 for(Num i=0;i&lt;Iter;++i)
  #pragma omp parallel for schedule(runtime)
  for(Num num=0;num&lt;Iter;++num)
   out=out*Base+tmp,tmp=tmp*Base+num;
 while(true){
  #pragma omp parallel for schedule(runtime)
  for(Num num=0;num&lt;Iter;++num)
   out=out*Base+tmp,tmp=tmp*Base+num;
  cout.write((char*)&amp;out,sizeof(out));
 }
}


For computers with one CPU:

#include&lt;chrono&gt;
#include&lt;iostream&gt;
#include&lt;thread&gt;
using namespace std;

#define Nano 1
#define Mili 7
#define Base 7
#define Thrs 2

typedef unsigned char      Num;
typedef unsigned long long Out;

volatile Out out,tmp;

void inline thr(Num const num){
 while(true)
  out=out*Base+tmp,tmp=tmp*Base+num;
}

int main(){
 thread ths[Thrs];
  for(Num i=0;i&lt;Thrs;++i)
   ths[i]=thread(thr,i);
 this_thread::sleep_for(chrono::milliseconds(Mili));
 while(true)
  cout.write((char*)&amp;out,sizeof(out)),
  this_thread::sleep_for(chrono::nanoseconds(Nano));
}
A true random number generator (TRNG) is a source of bits such that each bit has a probability of exactly 1/2 of being 1. Your code is obviously not a TRNG since its bias will heavily depend on the timing of operations.

A pseudo-random number generator (PRNG) is a deterministic algorithm that produces bits which satisfy statistical tests designed to verify randomness. Your code is obviously not deterministic so it is not a PRNG.

What you have here is a source of entropy: a bit stream which is not fully deterministic. You're measuring the timing of your program which depends on the synchronization between wall time and the CPU, so you're using jitter as a source of entropy. 

CPU jitter may be a potential source of entropy. This paper by Stephan Müller analyzes CPU jitter on an x86 CPU. It has acceptable statistical properties if done right. However, there is a far cry from having acceptable statistical properties to being a good entropy source. The Linux kernel maintainers debated whether to include Müller's code as an entropy source, and concluded against it. They found two problems:


Having good statistical properties is good enough for some applications, but it is not good enough for security. For security, unpredictability is necessary. Even a knowledgeable adversary must not be able to reproduce the output. That includes, for example, an adversary who has the exact same hardware running the exact same program.
The CPU, in fine, does not contain much if any actual physical source of entropy. At the physical level, it's pretty much a deterministic system, albeit an extremely complex one which is difficult to analyze fully. It's unclear whether the physical uncertainties are enough to reach macroscopic levels.


To make things worse (much worse!) your implementation of CPU jitter measurement is deeply flawed. CPU jitter randomness is based on the lack of synchronization between the real-time clock (RTC) and the CPU's clock. But your code doesn't go very far in this direction: it spends most of its time doing sleep_for()! sleep_for() is based on interrupts driven by the RTC, and so are context switches. Confronting the RTC with itself is fully predictable, so the only source of unpredictability is the timing of the few computations that you make.

I haven't made any mathematical analysis of your computations (what you do with out). The only reason I can see to use multiplication here is to exercise different parts of the CPU to increase jitter. You should document this kind of design choices.

An obvious potential problem with your function is that it's prone to short cycles. The transformation (out, tmp) → (out*Base+tmp, tmp*Base+num) has cycles; if you fall into them you'll emit repetitions for a while until the scheduler hits. Just for fun, I ran your code and inspected the output visually, which is degree 0 of statistical testing (serious statistical testing uses tools that run for hours). The single-CPU version emitted sequences of zeroes () now and then… that's an obvious failure.

0000c9f0  5c 4d 68 41 e1 95 77 a6  17 2e bb 7a c6 37 d6 27 
0000ca00  54 a4 7f f0 5f ee 5b fc  54 a4 7f f0 5f ee 5b fc 
*
0000cbb0  a1 48 55 36 71 47 4b 75  4f a1 8d c1 60 fc c8 f0 
0000cbc0  52 f5 22 43 e1 1a c0 4d  52 f5 22 43 e1 1a c0 4d 
0000cbd0  52 f5 22 43 e1 1a c0 4d  74 47 ad 9f bd ee 5f 90 
0000cbe0  74 47 ad 9f bd ee 5f 90  74 47 ad 9f bd ee 5f 90 
*
0000cc40  74 47 ad 9f bd ee 5f 90  e3 2e c7 50 a8 84 5a 1c 
0000cc50  fb ea 92 19 2f 6c 98 8e  0b 6a 7a 9a ac 59 87 03 
0000cc60  73 ac 9f 43 2f 52 ab e1  2b d8 86 ab 7b 97 98 fc 


(The first column is the offsets, then , all in hex. A * stands for a sequence of all-zero lines.)

On the programming side, you should initialize all variables. Leaving variables uninitialized doesn't increase entropy (they're predictable on a given platform), makes your program harder to analyze, and allows the compiler to optimize parts of your code away (for example, since you can't distinguish between a final value of out that was produced from a particular starting value, and a final value that was produced from a different starting value, the compiler is allowed to perform no computation until the first time the value of out is written to). Also note that operations like out=out*Base+tmp are not performed atomically, there can be a context switch between the time out is read and the time out is written to, in which case the work of the other thread(s) is be overwritten.

Note: sometimes “TRNG” is used to mean a source of entropy, which I discuss below. An actual RNG can be built on top of a source of entropy (preferably multiple independent sources) by seeding a PRNG with the source of entropy. By this very weak definition, you have a TRNG, but as we've seen one that's neither good nor new.

All in all, you seem to be trying to generate random numbers by flailing around in the dark. That doesn't work. Generating random numbers is very difficult. In order to be taken seriously, a random number generator needs to come with a detailed analysis, including rationales for each sources, collected statistical data, mathematical models, etc. Not a code dump. Showing that you did no research by demonstrating ignorance of common terminology doesn't help your credibility either.