CPU RAM Jitter Driven RNG Data Source
using System;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Threading;
public class RngJitterSource : RandomNumberGenerator
{
/// <summary>
/// Recalculate buffer every 1000 milliseconds
/// </summary>
private const int ReSecureThresholdBf = 1000;
private readonly SHA3ModInt _algorithm;
private readonly object _cacheLock = new object();
private readonly int _moveSize;
/// <summary>
/// Just in case you need access to the underlying data
/// </summary>
public readonly JitterEx Jitter;
private readonly Stopwatch tmr;
private byte[] _cacheBuffer;
private int _cacheSize;
private volatile int _ptr;
private volatile int BytesRemainingInCache;
/// <summary>
/// If you want to use this as a flat memory pool
/// Use in conjunction with DataReady -- DataReady.WaitOne(); -- use data
/// </summary>
public volatile byte[] Cache;
public int cacheFills;
private Thread CacheThread;
/// <summary>
/// See Cache above
/// </summary>
public AutoResetEvent DataReady = new AutoResetEvent(false);
private bool Filled;
public int ResecureCount;
public RngJitterSource() : this(1024 * 1024, 1024, 256, 4)
{
}
public RngJitterSource(int cacheSize) : this(cacheSize, 1024, 256, 4)
{
}
public RngJitterSource(int cacheSize, int seedSize) : this(cacheSize, seedSize, 256, 4)
{
}
public RngJitterSource(int cacheSize, int seedSize, int sha3Size) : this(cacheSize, seedSize, sha3Size, 4)
{
}
public RngJitterSource(int cacheSize, int seedSize, int sha3Size, int sha3Rounds)
{
_cacheSize = cacheSize;
Jitter = new JitterEx();
_cacheBuffer = new byte[seedSize];
Jitter.GetBytes(_cacheBuffer);
Cache = new byte[_cacheSize];
_ptr = 0;
BytesRemainingInCache = 0;
_algorithm = new SHA3ModInt(sha3Size, sha3Rounds);
_moveSize = _algorithm.ComputeHash(2.GetBytes()).Length;
Filled = false;
tmr = new Stopwatch();
CacheThread = new Thread(KeepFullCache) {Priority = ThreadPriority.Highest};
CacheThread.Start();
}
public void Abort()
{
CacheThread.Abort();
}
protected override void Dispose(bool disposing)
{
_algorithm.Dispose();
}
public override void GetBytes(byte[] data)
{
if (data.Length > _cacheSize)
{
_cacheSize = data.Length;
Cache = new byte[_cacheSize];
_ptr = 0;
BytesRemainingInCache = 0;
if (CacheThread.IsAlive)
CacheThread.Abort();
DataReady = new AutoResetEvent(false);
CacheThread = new Thread(KeepFullCache) {Priority = ThreadPriority.Highest};
CacheThread.Start();
}
while (_ptr < data.Length)
Thread.Sleep(10);
DataReady.WaitOne();
Buffer.BlockCopy(Cache, _ptr - data.Length, data, 0, data.Length);
_ptr -= data.Length;
BytesRemainingInCache -= data.Length;
}
private void KeepFullCache()
{
while (true)
if (BytesRemainingInCache < _moveSize)
lock (_cacheLock)
{
var moveSize = _moveSize;
cacheFills++;
var bufferFills = 0;
tmr.Start();
while (true)
{
bufferFills++;
if (tmr.Elapsed.TotalMilliseconds >= ReSecureThresholdBf)
{
Jitter.GetBytes(_cacheBuffer);
tmr.Restart();
ResecureCount++;
}
var remainingBytesToMove = _cacheSize - _ptr;
if (remainingBytesToMove < moveSize)
moveSize = remainingBytesToMove;
if (remainingBytesToMove <= 0 || _ptr >= _cacheSize)
break;
_cacheBuffer = _algorithm.ComputeHash(_cacheBuffer);
Buffer.BlockCopy(_cacheBuffer, 0, Cache, _ptr, moveSize);
_ptr += moveSize;
}
tmr.Stop();
_ptr = _cacheSize;
BytesRemainingInCache = _cacheSize;
DataReady.Set();
}
else
DataReady.Set();
}
}