Random64csp.cs

64 Bit Random Number Generator Using RNGCryptoServiceProvider

using System;
using System.Security.Cryptography;
[Serializable]
public class Random64csp : RandomNumberGenerator
{
    private byte[] _buffer;
    private RNGCryptoServiceProvider _crng;
    private double _dBi;
    private ulong UpperLimit = ulong.MaxValue;
    public Random64csp()
    {
        SetDataUse = 8;
        _crng = new RNGCryptoServiceProvider();
    }
    
    public Random64csp(int dataSize)
    {
        SetDataUse = dataSize;
        _crng      = new RNGCryptoServiceProvider();
    }
    
    public int SetDataUse
    {
        get => _buffer.Length;
        set
        {
            var v = value;
            if (v < 1 || v > 8 || v == 3 || v == 5 || v == 6 || v == 7)
                throw new ArgumentException($"Value {v} must be either 1 or 2 or 4 or 8");
            switch (v)
            {
                case 1:
                    _dBi = 1.0D / byte.MaxValue;
                    UpperLimit = byte.MaxValue;
                    _buffer = new byte[1];
                    break;
                case 2:
                    _dBi = 1.0D / ushort.MaxValue;
                    UpperLimit = ushort.MaxValue;
                    _buffer = new byte[2];
                    break;
                case 4:
                    _dBi = 1.0D / uint.MaxValue;
                    UpperLimit = uint.MaxValue;
                    _buffer = new byte[4];
                    break;
                case 8:
                    _dBi = 1.0D / ulong.MaxValue;
                    UpperLimit = ulong.MaxValue;
                    _buffer = new byte[8];
                    break;
                default:
                    _dBi = 1.0D / ulong.MaxValue;
                    UpperLimit = ulong.MaxValue;
                    _buffer = new byte[8];
                    break;
            }
        }
    }
    /// <summary>
    ///     Will generate only odd values
    /// </summary>
    public bool OddsOnly
    {
        get;
        set;
    }
    private double Sample()
    {
        ulong Internal()
        {
            _crng.GetBytes(_buffer);
            return BufferToLong(_buffer);
        }
        return Internal() * _dBi;
    }
    public ulong Next(ulong minValue, ulong maxValue)
    {
        var sa = Sample();
        var fi = (double)(maxValue - minValue + minValue);
        var n = (ulong)(sa * fi);
        n = !OddsOnly ? n : n | 1;
        if (n < minValue)
            return Next(minValue, maxValue);
        return n;
    }
    public ulong Next(ulong maxValue)
    {
        return Next(0, maxValue);
    }
    public ulong Next()
    {
        return Next(0, UpperLimit);
    }
    public unsafe double NextDouble()
    {
        var buf = new byte[8];
        GetBytes(buf);
        fixed (byte* ptr = buf)
        {
            return *(ulong*)ptr * _dBi * ulong.MaxValue;
        }
    }
    public char[] GetNextCharArray(int size)
    {
        var xbc = new byte[1];
        var ca = new char[size];
        var ptr = 0;
        do
        {
            _crng.GetBytes(xbc);
            var c = xbc[0];
            if (c >= 32 && c <= 127)
                ca[ptr++] = (char)c;
        } while (ptr < size);
        return ca;
    }
    public char[] GetNextCharArrayX(int size)
    {
        var xbc = new byte[2];
        var ca = new char[size];
        var ptr = 0;
        do
        {
            _crng.GetBytes(xbc);
            ca[ptr++] = Convert.ToChar(xbc.ToShort());
        } while (ptr < size);
        return ca;
    }
    public byte[] GetNextByteArray(int size)
    {
        var ba = new byte[size];
        _crng.GetBytes(ba);
        return ba;
    }
    /// <summary>
    ///     Next(0,2)==0?false:true; has a distribution error of 1% weighted toward zero.
    ///     The distribution error here is 0.000000046% which is statistically insignificant in this context.
    /// </summary>
    /// <param name="size"></param>
    /// <returns></returns>
    public bool[] GetNextBoolArrayLimit(int size)
    {
        var ba = new bool[size];
        const uint ll = uint.MaxValue >> 1;
        for (var i = 0; i < size; ++i)
            ba[i] = Next(0, uint.MaxValue) > ll;
        return ba;
    }
    public byte[] GetNextByteArrayLimit(int size, ulong minValue, ulong maxValue)
    {
        var ba = new byte[size];
        for (var i = 0; i < size; ++i)
            ba[i] = (byte)Next(minValue, maxValue);
        return ba;
    }
    public ushort[] GetNextUShortArrayLimit(int size, ulong minValue, ulong maxValue)
    {
        var ba = new ushort[size];
        for (var i = 0; i < size; ++i)
            ba[i] = (ushort)Next(minValue, maxValue);
        return ba;
    }
    public uint[] GetNextUIntArrayLimit(int size, ulong minValue, ulong maxValue)
    {
        var ba = new uint[size];
        for (var i = 0; i < size; ++i)
            ba[i] = (uint)Next(minValue, maxValue);
        return ba;
    }
    public ulong[] GetNextULongArrayLimit(int size, ulong minValue, ulong maxValue)
    {
        var ba = new ulong[size];
        for (var i = 0; i < size; ++i)
            ba[i] = Next(minValue, maxValue);
        return ba;
    }
    public string GetRandomString(int minLen, int maxLen)
    {
        if (minLen == maxLen)
            return new string(GetNextCharArray(minLen));
        return new string(GetNextCharArray((int)Next((ulong)minLen, (ulong)maxLen)));
    }
    public override void GetBytes(byte[] data)
    {
        if (data == null)
            throw new ArgumentException("The buffer cannot be null.");
        _crng.GetBytes(data);
    }
    public void NextBytes(byte[] buffer)
    {
        if (buffer == null)
            throw new ArgumentNullException("The buffer cannot be null.");
        for (var index = 0; index < buffer.Length; ++index)
            buffer[index] = (byte)(Sample() * byte.MaxValue + 1);
    }
    public override void GetNonZeroBytes(byte[] buffer)
    {
        if (buffer == null)
            throw new ArgumentNullException("The buffer cannot be null.");
        var index = 0;
        do
        {
            var v = (byte)(Sample() * byte.MaxValue + 1);
            if (v > 0)
            {
                buffer[index] = v;
                index++;
            }
        } while (index < buffer.Length);
    }
    private unsafe ulong BufferToLong(byte[] buffer)
    {
        var len = buffer.Length;
        if (len < 1 || len > 8)
            throw new ArgumentException($"The array length {len} must be between 1 and 8");
        fixed (byte* Ptr = &buffer[0])
        {
            switch (len)
            {
                case 1:
                    return *Ptr;
                case 2:
                    return (uint)(*Ptr | (Ptr[1] << 8));
                case 3:
                    return (uint)(*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16));
                case 4:
                    return (uint)(*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24));
                case 5:
                    return (uint)(*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong)Ptr[4] << 32);
                case 6:
                    return (uint)(*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong)(Ptr[4] | (Ptr[5] << 8)) << 32);
                case 7:
                    return (uint)(*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong)(Ptr[4] | (Ptr[5] << 8) | (Ptr[6] << 16)) << 32);
                case 8:
                    return (uint)(*Ptr | (Ptr[1] << 8) | (Ptr[2] << 16) | (Ptr[3] << 24)) | ((ulong)(Ptr[4] | (Ptr[5] << 8) | (Ptr[6] << 16) | (Ptr[7] << 24)) << 32);
                default:
                    return 0;
            }
        }
    }
}

Random64d.cs

64 Bit Version of Random

using System;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
[Serializable]
public class Random64d : RandomNumberGenerator
{
    private const                    double                   DBi  = 1.0 / 9223372036854775807;
    private const                    double                   DBui = 1.0 / ulong.MaxValue;
    private readonly                 Random                   _r1;
    private readonly                 Random                   _r2;
    [NonSerialized] private readonly RNGCryptoServiceProvider _rng = new RNGCryptoServiceProvider();
    private                          RNumber                  _rNumber;
    public Random64d() : this(((long) (uint) Environment.TickCount << 32) | (uint) Environment.TickCount)
    {
    }
    public Random64d(long Seed)
    {
        var Seed0 = (int) (((Seed ^ 0x86B28CAB) << 16) & 0x7fffffff);
        var Seed1 = (int) (Seed                        & 0x7fffffff);
        _r1 = new Random(Seed0);
        _r2 = new Random(Seed1);
    }
    public long InternalSample()
    {
        _rNumber.n1 = _r1.Next();
        _rNumber.n2 = _r2.Next();
        return _rNumber.total;
    }
    private double GetSampleForLargeRange()
    {
        var value = InternalSample();
        if (InternalSample() % 2 == 0)
            value = -value;
        return (value + 4611686018427387903.0) / 9223372036854775807.0;
    }
    private double Sample()
    {
        return InternalSample() * DBi;
    }
    public long Next()
    {
        return InternalSample();
    }
    public long Next(long minValue, long maxValue)
    {
        if (minValue > maxValue)
            throw new ArgumentException("maxValue must be greater than or equal to minValue");
        var num = (ulong) maxValue - (ulong) minValue;
        if (num <= long.MaxValue)
            return (long) (Sample() * num) + minValue;
        return (long) ((ulong) (GetSampleForLargeRange() * num) + (ulong) minValue);
    }
    public ulong Next(ulong minValue, ulong maxValue)
    {
        if (minValue > maxValue)
            throw new ArgumentException("maxValue must be greater than or equal to minValue");
        var num = maxValue - minValue;
        return (ulong) (InternalSample() * DBui * num) + minValue;
    }
    public long Next(long maxValue)
    {
        if (maxValue < 0)
            throw new ArgumentException("maxValue must be greater than zero.");
        return (long) (Sample() * maxValue);
    }
    public ulong Next(ulong maxValue)
    {
        return (ulong) (InternalSample() * DBui * maxValue);
    }
    public double NextDouble()
    {
        return Sample();
    }
    public byte[] GetNextByteArray(int size)
    {
        var ba = new byte[size];
        _rng.GetBytes(ba);
        return ba;
    }
    public byte[] GetNextByteArrayFn(int size)
    {
        var ba = new byte[size];
        for (var i = 0; i < size; ++i)
            ba[i] = (byte) Next(0, 256);
        return ba;
    }
    public char[] GetNextCharArray(int size)
    {
        var ca = new char[size];
        for (var i = 0; i < size; ++i)
            ca[i] = (char)Next(32, 128);
        return ca;
    }
    public string GetRandomString(int minLen, int maxLen)
    {
        if (minLen == maxLen)
            return new string(GetNextCharArray(minLen));
        return new string(GetNextCharArray((int) Next(minLen, maxLen)));
    }
    public override void GetBytes(byte[] data)
    {
        if (data == null)
            throw new ArgumentException("The buffer cannot be null.");
        _rng.GetBytes(data);
    }
    [StructLayout(LayoutKind.Explicit, Size = 8, Pack = 1)]
    [Serializable]
    public struct RNumber
    {
        [FieldOffset(0)] public long n1;
        [FieldOffset(4)] public long n2;
        [FieldOffset(0)] public long total;
    }
}

JitterEx.cs

//#define TEST
using System;
using System.Diagnostics;
using System.Management;
using System.Runtime.CompilerServices;
using System.Threading;
[Serializable]
public class JitterEx
{
    private const    int    DesaturationLoopLimit = 500;
    private const    int    UpperCpuLoadLimit     = 90;
    private const    int    LowerCpuLoadLimit     = 10;
    private static   bool   _scaleSet;
    private readonly int    _bufferSize;
    private readonly object _lock = new object();
    private readonly Random _prng;
    private          byte[] _rngCache;
    private          int    _tscLoopLimitCpu  = 10;
    private          int    _tscSampleSizeRam = 18;
    public JitterEx(int buffersize, bool randomize = false)
    {
        _bufferSize = buffersize;
        _rngCache   = new byte[_bufferSize];
        _prng       = new Random();
        Randomize   = randomize;
        SetScale();
    }
    public bool Randomize
    {
        get;
        set;
    }
#if TEST
    public void TestListF()
    {
        var rlst = new List<List<(byte[], int)>>();
        for (var i = 0; i < TestList.Count; i++)
        {
            var f = TestList[i];
            for (var j = i + 1; j < TestList.Count; j++)
            {
                var s = TestList[j];
                rlst.Add(new BMPartialPatternSearch(3).SearchPartialAll(f, s));
            }
        }
    }
#endif
    [MethodImpl(MethodImplOptions.NoOptimization)]
    private float GetCpuSpeed()
    {
        void Loop()
        {
            var i = 0;
            while (true)
                i = i + 1 - 1;
        }
        var cpuCounter = new PerformanceCounter("Processor Information", "% Processor Performance", "_Total");
        var cpuValue   = cpuCounter.NextValue();
        var loop       = new Thread(() => Loop()) {Priority = ThreadPriority.Highest};
        var Speed      = 0f;
        lock (_lock)
        {
            loop.Start();
            Thread.Sleep(60);
            cpuValue = cpuCounter.NextValue();
            loop.Abort();
        }
        foreach (ManagementObject obj in new ManagementObjectSearcher("SELECT *, Name FROM Win32_Processor").Get())
        {
            var v = Convert.ToSingle(obj["MaxClockSpeed"]);
            Speed = v / 1000 * cpuValue / 100;
        }
        return Speed;
    }
    /// <summary>
    ///     This is a fairly arbitrary value which is based on the CPU speed. 4.7 is the speed on which the tests are based.
    /// </summary>
    private void SetScale()
    {
        if (_scaleSet)
            return;
        _scaleSet = true;
        const float baseFreq = 4.7f;
        var         thisFreq = GetCpuSpeed();
        var         rat      = baseFreq / thisFreq;
        _tscLoopLimitCpu  = (int) Math.Ceiling(_tscLoopLimitCpu  * rat);
        _tscSampleSizeRam = (int) Math.Ceiling(_tscSampleSizeRam * rat);
    }
    private void LoadBlock()
    {
        var DesaturationLoops = 0;
        var dump              = CpuTotalPc.CPULoad;
        do
        {
            Thread.Sleep(0);
            DesaturationLoops++;
        } while (DesaturationLoops < DesaturationLoopLimit && ((int) CpuTotalPc.CPULoad > UpperCpuLoadLimit || (int) CpuTotalPc.CPULoad < LowerCpuLoadLimit));
    }
    [MethodImpl(MethodImplOptions.NoInlining)]
    private byte[] GetBufferCpu()
    {
        void Loop()
        {
            var x = 0;
            for (var i = 0; i < _tscLoopLimitCpu; i++)
                x = x + 1 - 1;
        }
        var jitterBuffer = new byte[_bufferSize];
        var ptr          = 0;
        LoadBlock();
        lock (_lock)
        {
            var start = Rdtsc.TimestampP();
            do
            {
                var loop = new Thread(() => Loop()) {Priority = ThreadPriority.Highest};
                loop.Start();
                loop.Join();
                var stop = Rdtsc.TimestampP();
                Buffer.BlockCopy((100000.0 / ((stop - start) * 100000.0)).GetBytes(), 0, jitterBuffer, ptr, 4);
                start =  stop;
                ptr   += 4;
            } while (ptr < _bufferSize);
            return jitterBuffer;
        }
    }
    [MethodImpl(MethodImplOptions.NoInlining)]
    private unsafe byte[] GetBufferRam()
    {
        void Loop()
        {
            byte tempByte;
            fixed (byte* p1 = _rngCache)
            {
                var x1 = p1;
                for (var j = 0; j < _tscSampleSizeRam; ++j, ++x1)
                    tempByte = *x1;
            }
        }
        LoadBlock();
        var jitterBuffer = new byte[_bufferSize];
        lock (_lock)
        {
            if (_rngCache.Length != _bufferSize)
                _rngCache = new byte[_bufferSize];
            _prng.NextBytes(_rngCache);
            var ptr   = 0;
            var start = Rdtsc.TimestampP();
            while (true)
            {
                do
                {
                    var loop = new Thread(() => Loop()) {Priority = ThreadPriority.Highest};
                    loop.Start();
                    loop.Join();
                    var stop = Rdtsc.TimestampP();
                    Buffer.BlockCopy((100000.0 / ((stop - start) * 100000.0)).GetBytes(), 0, jitterBuffer, ptr, 4);
                    start =  stop;
                    ptr   += 4;
                    if (ptr < _bufferSize)
                    {
                        if (_rngCache.Length != _bufferSize)
                            _rngCache = new byte[_bufferSize];
                        _prng.NextBytes(_rngCache);
                    }
                } while (ptr < _bufferSize);
                return jitterBuffer;
            }
        }
    }
    public byte[] GetBuffer()
    {
        var firstBuffer = GetBufferCpu();
#if TEST
        ///Weighting add 15%, perfection is not what we are looking for here.
        var lim = _bufferSize <= 256 ? _bufferSize / 256.0 * 85.0 : 6.8;
        if (ent.Entropy(firstBuffer) < lim)
            throw new Exception("Error CPU Jitter Buffer Contains only zeros.");
#endif
        var secondBuffer = GetBufferRam();
#if TEST
        if (ent.Entropy(secondBuffer) < lim)
            throw new Exception("Error CPU Jitter Buffer Contains only zeros.");
#endif
        var finalBuffer = new byte[_bufferSize];
        for (var j = 0; j < _bufferSize; ++j)
            finalBuffer[j] = (byte) (firstBuffer[j] ^ secondBuffer[j]);
#if TEST
        if (ent.Entropy(finalBuffer) < lim)
            throw new Exception("Error CPU Jitter Buffer Contains only zeros.");
#endif
        if (Randomize)
        {
            var ula    = CreateNoiseArrays(finalBuffer);
            var rBlock = new byte[ula.Length * 8];
            Buffer.BlockCopy(ula, 0, rBlock, 0, ula.Length * 8);
#if TEST
            if (_bufferSize >= 256)
            {
                var loop = new Thread(() =>
                {
                    if (!rBlock.ChiSquaredTest().isRandom)
                        MessageBoxEx.Show("Warning", "Block not random.", MessageBoxExButtons.OK, MessageBoxExIcon.Warning);
                }) {Priority = ThreadPriority.Highest};
                loop.Start();
            }
            TestList.Add(rBlock);
#endif
            return rBlock;
        }
#if TEST
        if (_bufferSize >= 256)
        {
            var loop = new Thread(() =>
            {
                if (!finalBuffer.ChiSquaredTest().isRandom)
                    MessageBoxEx.Show("Warning", "Block not random.", MessageBoxExButtons.OK, MessageBoxExIcon.Warning);
            }) {Priority = ThreadPriority.Highest};
            loop.Start();
        }
        TestList.Add(finalBuffer);
#endif
        return finalBuffer;
    }
    private ulong[] ByteArrayToULongArray(byte[] ba, int finalSize)
    {
        var minSize = ba.Length / 8;
        if (finalSize < minSize)
            finalSize = minSize;
        ba = PadULong(ba);
        var result = new ulong[finalSize];
        for (var i = 0; i < ba.Length; i += 8)
            Buffer.BlockCopy(ba, i, result, i, 8);
        return result;
    }
    private static byte[] PadULong(byte[] ba)
    {
        var s = ba.Length % 8;
        switch (s)
        {
            case 0:
                break;
            case 1:
                Array.Resize(ref ba, ba.Length + 7);
                ba[ba.Length - 1] = 0x80;
                ba[ba.Length - 2] = 0x80;
                ba[ba.Length - 3] = 0x80;
                ba[ba.Length - 4] = 0x80;
                ba[ba.Length - 5] = 0x80;
                ba[ba.Length - 6] = 0x80;
                ba[ba.Length - 7] = 0x80;
                break;
            case 2:
                Array.Resize(ref ba, ba.Length + 6);
                ba[ba.Length - 1] = 0x80;
                ba[ba.Length - 2] = 0x80;
                ba[ba.Length - 3] = 0x80;
                ba[ba.Length - 4] = 0x80;
                ba[ba.Length - 5] = 0x80;
                ba[ba.Length - 6] = 0x80;
                break;
            case 3:
                Array.Resize(ref ba, ba.Length + 5);
                ba[ba.Length - 1] = 0x80;
                ba[ba.Length - 2] = 0x80;
                ba[ba.Length - 3] = 0x80;
                ba[ba.Length - 4] = 0x80;
                ba[ba.Length - 5] = 0x80;
                break;
            case 4:
                Array.Resize(ref ba, ba.Length + 4);
                ba[ba.Length - 1] = 0x80;
                ba[ba.Length - 2] = 0x80;
                ba[ba.Length - 3] = 0x80;
                ba[ba.Length - 4] = 0x80;
                break;
            case 5:
                Array.Resize(ref ba, ba.Length + 3);
                ba[ba.Length - 1] = 0x80;
                ba[ba.Length - 2] = 0x80;
                ba[ba.Length - 3] = 0x80;
                break;
            case 6:
                Array.Resize(ref ba, ba.Length + 2);
                ba[ba.Length - 1] = 0x80;
                ba[ba.Length - 2] = 0x80;
                break;
            case 7:
                Array.Resize(ref ba, ba.Length + 1);
                ba[ba.Length - 1] = 0x80;
                break;
        }
        return ba;
    }
    private static void Extrude(ulong[] x)
    {
        var size = x.Length;
        for (var i = 0; i < size; i++)
        {
            ulong n = 0;
            var   j = 0;
            while (j < size)
            {
                n ^= x[j];
                ++j;
            }
            x[i] = (n << 1) | (n >> 56);
        }
    }
    private ulong[] CreateNoiseArrays(byte[] ba)
    {
        var ula = ByteArrayToULongArray(ba, ba.Length / 8);
        Extrude(ula);
        return ula;
    }
    internal class EntropyI
    {
        private const double NaturalLogOfTwo = 0.69314718055994530941723212145818; //Math.Log(2);
        /// <summary>
        ///     Get the Entropy from 1 to 100% 1 being very ordered data,
        ///     100% being very disordered data.
        /// </summary>
        public double Entropy(byte[] a)
        {
            var h = new int[256];
            var l = a.Length;
            for (var i = 0; i < l; ++i)
                h[a[i]]++;
            var e = 0.0;
            for (var i = 0; i < 256; ++i)
            {
                var v = h[i];
                if (v <= 0)
                    continue;
                var r = v             / (double) l;
                e -= r * (Math.Log(r) / NaturalLogOfTwo);
            }
            return e / 8.0 * 100.0;
        }
    }
#if TEST
    private EntropyI     ent = new EntropyI();
    private List<byte[]> TestList = new List<byte[]>();
#endif
}