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(); } }