BouncyCastle style ThreadedSeedGenerator I've written a BouncyCastle style threaded seeder and was wondering about the predictability of the data the program generates.

The reason I'm not simply using BouncyCastle is because security isn't a concern, I don't want to use a whole library just for one function, and this code is MUCH faster.

The idea is to make several threads which operate on a circular buffer (a simple array), where each thread performs a different operation on the data in the buffer. The randomness comes from thread scheduling irregularities in the OS.

How much randomness can I expect from a mechanism like this?

C# code:

using System;
using System.Threading;

class ThreadedSeeder
{
    static public ulong[] buffer = new ulong[1024];
    static public bool doThread = true;

    public ThreadedSeeder()
    {
        MakeThread(Add);
        MakeThread(Multiply);
        MakeThread(Xorshift);

        Thread.Sleep(10);

        doThread = false;
    }

    static private void MakeThread(ThreadStart a)
    {
        Thread b = new Thread(a)
        {
            Priority = ThreadPriority.Lowest
        };

        b.Start();
    }

    static private void Add()
    {
        int i = 0;

        while (doThread)
        {
            buffer[i &amp; 1023] += (ulong)DateTime.UtcNow.Ticks;
            i++;
        }
    }

    static private void Multiply()
    {
        int i = 0;

        while (doThread)
        {
            buffer[i &amp; 1023] *= 6364136223846793005;
            i++;
        }
    }

    static private void Xorshift()
    {
        int i = 0;

        while (doThread)
        {
            ulong y = buffer[i &amp; 1023];

            y ^= (y &lt;&lt; 13);
            y ^= (y &gt;&gt; 17);
            y ^= (y &lt;&lt; 5);
            buffer[i &amp; 1023] = y;

            i++;
        }
    }
}
The approach is deeply flawed in many ways.


It is very plausible that the whole buffer is returned at zero under heavy load, which is something that an attacker can often intentionally cause (e.g. with a flood of network traffic requiring high CPU load; starting a number of https connections comes to mind). That's likely to be a practical disaster.
Mechanism: the three threads launched by ThreadedSeeder are set to Lowest-priority, thus it is reasonable that they won't do anything before the Thread.Sleep(10). If the machine has higher-priority-than-Lowest things do during that pause, execution can proceed to doThread = false before the Add thread has ever tested doThread, thus with Add performing nothing related to buffer. The same could hold for Multiply and Shift too, but that's immaterial, as these threads can not un-zero buffer even if they run.
More generally there is little insurance about the number of times DateTime.UtcNow.Ticks is called; that could be very few, including less than once per buffer entry, thus always leaving all the other entries at zero. The busiest the machine, the more likely it is that a buffer entry has no, one, or very few readings of DateTime.UtcNow.Ticks to influence it.
I see no mechanism preventing Multiply or Xorshift from competing with Add about what element of buffer it operates on, and thus void a change Add makes meanwhile. This is an uncontrolled race condition, and it can loose some of the entropy gathered.
DateTime.UtcNow.Ticks can be closely approximated by adversaries. That's supposed to be the UTC time, which is not a secret. Further, common mechanisms such as RFC&nbsp;7323 high-resolution TCP time stamps allow to find what a particular machine believes the UTC time is, even when it is poorly synchronized. And when the machine is under light load, with one CPU running each thread including Add at full blast, the difference between readings will be reasonably repeatable.
The transformation made from DateTime.UtcNow.Ticks to what is in each element of the buffer is one among relatively few public transformations. And each of these possible transformations is trivially reversible (modular multiplication by an odd constant modulo a power of two is reversible in Multiply, as well as each of the three bitwise operations in Xorshift). Combined with 4, it trivially allows a very selective distinguisher on each buffer element output whenever there is only a single DateTime.UtcNow.Ticks that influenced it, also revealing which transformation occurred. It looks like this could be extended to a few such influences.
Neither the code nor the text of the question shows any effort to create explicit diffusion of the entropy gathered: elements of buffer are never mixed. Absent such mixing or/and post-conditioning before use of buffer, some degree of 2/4/5 can be a practical disaster.
Timing execution won't gather any entropy in some precisely controlled execution environments, including VMs/simulators used by hardware engineers or reverse-engineering of malware. Ultimately, the state of buffer on output, and whatever is deterministically derived from that, will dependent only on when the task is launched.