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

LongLong.cs

Int64 Bit Class

Jun-11,2021: Obsolete Use xIntX Instead.

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
/// <summary>
///     Used to verify correct mathematical operations before extending to 128, 256, 512, 1024, and 2048 versions
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential, Pack = 1)]
[TypeConverter(typeof(LongLongConverter))]
[DebuggerDisplay("{DDisplay}")]
public struct LongLong : IComparable<LongLong>, IComparable, IEquatable<LongLong>, IConvertible, IFormattable
{
    private ulong B64;
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private string DDisplay => ToString();
    public static LongLong Zero     = new LongLong(0);
    public static LongLong Ten      = new LongLong(10);
    public static LongLong One      = new LongLong(1);
    public static LongLong MaxValue = GetMaxValue();
    public static LongLong MinValue = GetMinValue();
    private static LongLong GetMaxValue()
    {
        return new LongLong(ulong.MaxValue);
    }
    private static LongLong GetMinValue()
    {
        return new LongLong(0);
    }
    public LongLong(LongLong value)
    {
        B64 = value.B64;
    }
    public LongLong(string value)
    {
        if (!TryParse(value, out var result))
            throw new Exception("TryParse Failed.");
        B64 = result.B64;
    }
    public LongLong(byte value)
    {
        B64 = value;
    }
    public LongLong(bool value)
    {
        B64 = (ulong) (value ? 1 : 0);
    }
    public LongLong(char value)
    {
        B64 = value;
    }
    public LongLong(decimal value)
    {
        if (value < 0)
            throw new Exception("Value must be a positive.");
        var bits = decimal.GetBits(value);
        B64 = (uint) bits[0];
        if (value < 0)
            B64 = ~B64;
    }
    public LongLong(double value) : this((decimal) value)
    {
    }
    public LongLong(float value) : this((decimal) value)
    {
    }
    public LongLong(short value)
    {
        if (value < 0)
            throw new Exception("Value must be a positive.");
        B64 = (ulong) value;
    }
    public LongLong(int value)
    {
        if (value < 0)
            throw new Exception("Value must be a positive.");
        B64 = (ulong) value;
    }
    public LongLong(long value)
    {
        if (value < 0)
            throw new Exception("Value must be a positive.");
        B64 = (ulong) value;
    }
    public LongLong(UInt128 value)
    {
        if (value < 0)
            throw new Exception("Value must be a positive.");
        B64 = value.B64;
    }
    public LongLong(sbyte value)
    {
        if (value < 0)
            throw new Exception("Value must be a positive.");
        B64 = (ulong) value;
    }
    public LongLong(ushort value)
    {
        B64 = value;
    }
    public LongLong(uint value)
    {
        B64 = value;
    }
    public LongLong(ulong value)
    {
        B64 = value;
    }
    public LongLong(Guid value) : this(value.ToByteArray())
    {
    }
    public LongLong(byte[] value)
    {
        if (value == null)
            throw new Exception("Value cannot be null.");
        if (value.Length != 64)
            throw new Exception("Values length must be 64 bytes.");
        B64 = BitConverter.ToUInt64(value, 0);
    }
    //public LongLong(ulong b64)
    //{
    //    B64 = b64;
    //}
    public LongLong(uint[] array)
    {
        if (array == null)
            throw new Exception("Array cannot be null.");
        var b64 = new byte[8];
        if (array.Length > 0)
        {
            Array.Copy(BitConverter.GetBytes(array[0]), 0, b64, 0, 4);
            if (array.Length > 1)
                Array.Copy(BitConverter.GetBytes(array[1]), 0, b64, 4, 4);
        }
        B64 = BitConverter.ToUInt64(b64, 0);
    }
    public int BitWidth
    {
        get
        {
            LongLong bitWidth = 1;
            var      v        = this;
            while ((v >>= 1) > 0)
                bitWidth++;
            if (bitWidth < 8)
                bitWidth = 8;
            while (bitWidth % 8 != 0)
                bitWidth++;
            return (int) bitWidth;
        }
    }
    public override int GetHashCode()
    {
        return B64.GetHashCode();
    }
    public override bool Equals(object obj)
    {
        return base.Equals(obj);
    }
    public bool Equals(LongLong obj)
    {
        return B64 == obj.B64;
    }
    public override string ToString()
    {
        return ToString(null, null);
    }
    public string ToString(string format)
    {
        return ToString(format, null);
    }
    public string ToString(string format, IFormatProvider formatProvider)
    {
        if (formatProvider == null)
            formatProvider = CultureInfo.CurrentCulture;
        if (!string.IsNullOrEmpty(format))
        {
            var ch = format[0];
            if (ch == 'x' || ch == 'X')
            {
                int.TryParse(format.Substring(1).Trim(), out var min);
                return ToHexString(ch == 'X', min);
            }
            if (ch != 'G' && ch != 'g' && ch != 'D' && ch != 'd')
                throw new NotSupportedException("Not supported format: " + format);
        }
        return ToString((NumberFormatInfo) formatProvider.GetFormat(typeof(NumberFormatInfo)));
    }
    private string ToHexString(bool caps, int min)
    {
        var bytes = ToByteArray().Invert();
        var sb    = new StringBuilder();
        var x     = caps ? "X" : "x";
        foreach (var b in bytes)
        {
            var hex = b.ToString($"{x}2");
            sb.Append(hex);
        }
        return sb.ToString();
    }
    private string ToString(NumberFormatInfo info)
    {
        var buf = ToByteArray();
        var bi  = new BigInteger(buf.Concat(new byte[] {0}).ToArray());
        return bi.ToString();
    }
    TypeCode IConvertible.GetTypeCode()
    {
        return TypeCode.Object;
    }
    bool IConvertible.ToBoolean(IFormatProvider provider)
    {
        return (bool) this;
    }
    byte IConvertible.ToByte(IFormatProvider provider)
    {
        return (byte) this;
    }
    char IConvertible.ToChar(IFormatProvider provider)
    {
        return (char) this;
    }
    DateTime IConvertible.ToDateTime(IFormatProvider provider)
    {
        throw new InvalidCastException();
    }
    decimal IConvertible.ToDecimal(IFormatProvider provider)
    {
        return (decimal) this;
    }
    double IConvertible.ToDouble(IFormatProvider provider)
    {
        return (double) this;
    }
    short IConvertible.ToInt16(IFormatProvider provider)
    {
        return (short) this;
    }
    int IConvertible.ToInt32(IFormatProvider provider)
    {
        return (int) this;
    }
    long IConvertible.ToInt64(IFormatProvider provider)
    {
        return (int) this;
    }
    public ulong ToUInt64(IFormatProvider provider)
    {
        return (ulong) this;
    }
    sbyte IConvertible.ToSByte(IFormatProvider provider)
    {
        return (sbyte) this;
    }
    float IConvertible.ToSingle(IFormatProvider provider)
    {
        return (float) this;
    }
    string IConvertible.ToString(IFormatProvider provider)
    {
        return ToString(null, provider);
    }
    public bool TryConvert(Type conversionType, IFormatProvider provider, out object value)
    {
        if (conversionType == typeof(bool))
        {
            value = (bool) this;
            return true;
        }
        if (conversionType == typeof(byte))
        {
            value = (byte) this;
            return true;
        }
        if (conversionType == typeof(char))
        {
            value = (char) this;
            return true;
        }
        if (conversionType == typeof(decimal))
        {
            value = (decimal) this;
            return true;
        }
        if (conversionType == typeof(double))
        {
            value = (double) this;
            return true;
        }
        if (conversionType == typeof(short))
        {
            value = (short) this;
            return true;
        }
        if (conversionType == typeof(int))
        {
            value = (int) this;
            return true;
        }
        if (conversionType == typeof(long))
        {
            value = (long) this;
            return true;
        }
        if (conversionType == typeof(sbyte))
        {
            value = (sbyte) this;
            return true;
        }
        if (conversionType == typeof(float))
        {
            value = (float) this;
            return true;
        }
        if (conversionType == typeof(string))
        {
            value = ToString(null, provider);
            return true;
        }
        if (conversionType == typeof(ushort))
        {
            value = (ushort) this;
            return true;
        }
        if (conversionType == typeof(uint))
        {
            value = (uint) this;
            return true;
        }
        if (conversionType == typeof(ulong))
        {
            value = (ulong) this;
            return true;
        }
        if (conversionType == typeof(byte[]))
        {
            value = ToByteArray();
            return true;
        }
        if (conversionType == typeof(Guid))
        {
            value = new Guid(ToByteArray());
            return true;
        }
        value = null;
        return false;
    }
    public static LongLong Parse(string value)
    {
        return Parse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
    }
    public static LongLong Parse(string value, NumberStyles style)
    {
        return Parse(value, style, NumberFormatInfo.CurrentInfo);
    }
    public static LongLong Parse(string value, IFormatProvider provider)
    {
        return Parse(value, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
    }
    public static LongLong Parse(string value, NumberStyles style, IFormatProvider provider)
    {
        if (!TryParse(value, style, provider, out var result))
            throw new Exception($"TryParse value {value} failure.");
        return result;
    }
    public static bool TryParse(string value, out LongLong result)
    {
        return TryParse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
    }
    public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out LongLong result)
    {
        result = Zero;
        if (string.IsNullOrEmpty(value))
            return false;
        if (value.StartsWith("x", StringComparison.OrdinalIgnoreCase))
        {
            style |= NumberStyles.AllowHexSpecifier;
            value =  value.Substring(1);
        }
        else
        {
            if (value.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
            {
                style |= NumberStyles.AllowHexSpecifier;
                value =  value.Substring(2);
            }
        }
        if ((style & NumberStyles.AllowHexSpecifier) == NumberStyles.AllowHexSpecifier)
            return TryParseHex(value, out result);
        return TryParseNum(value, out result);
    }
    private static bool TryParseHex(string value, out LongLong result)
    {
        if (value.Length > 128)
            throw new OverflowException();
        result = Zero;
        var pos = 0;
        for (var i = value.Length - 1; i >= 0; i--)
        {
            var   ch = value[i];
            ulong bch;
            if (ch >= '0' && ch <= '9')
                bch = (ulong) (ch - '0');
            else if (ch >= 'A' && ch <= 'F')
                bch = (ulong) (ch - 'A' + 10);
            else if (ch >= 'a' && ch <= 'f')
                bch = (ulong) (ch - 'a' + 10);
            else
                return false;
            if (pos < 64)
                result.B64 |= bch << pos;
            pos += 4;
        }
        return true;
    }
    private static bool TryParseNum(string value, out LongLong result)
    {
        result = Zero;
        foreach (var ch in value)
        {
            byte b;
            if (ch >= '0' && ch <= '9')
                b = (byte) (ch - '0');
            else
                return false;
            result =  Ten * result;
            result += b;
        }
        return true;
    }
    public object ToType(Type conversionType, IFormatProvider provider)
    {
        object value;
        if (TryConvert(conversionType, provider, out value))
            return value;
        throw new InvalidCastException();
    }
    ushort IConvertible.ToUInt16(IFormatProvider provider)
    {
        return Convert.ToUInt16(B64);
    }
    uint IConvertible.ToUInt32(IFormatProvider provider)
    {
        return Convert.ToUInt32(B64);
    }
    ulong IConvertible.ToUInt64(IFormatProvider provider)
    {
        return B64;
    }
    int IComparable.CompareTo(object obj)
    {
        return Compare(this, obj);
    }
    public static int Compare(LongLong left, object right)
    {
        if (right is LongLong)
            return Compare(left, (LongLong) right);
        if (right is bool)
            return Compare(left, new LongLong((bool) right));
        if (right is byte)
            return Compare(left, new LongLong((byte) right));
        if (right is char)
            return Compare(left, new LongLong((char) right));
        if (right is decimal)
            return Compare(left, new LongLong((decimal) right));
        if (right is double)
            return Compare(left, new LongLong((double) right));
        if (right is short)
            return Compare(left, new LongLong((short) right));
        if (right is int)
            return Compare(left, new LongLong((int) right));
        if (right is long)
            return Compare(left, new LongLong((long) right));
        if (right is sbyte)
            return Compare(left, new LongLong((sbyte) right));
        if (right is float)
            return Compare(left, new LongLong((float) right));
        if (right is ushort)
            return Compare(left, new LongLong((ushort) right));
        if (right is uint)
            return Compare(left, new LongLong((uint) right));
        if (right is ulong)
            return Compare(left, new LongLong((ulong) right));
        var bytes = right as byte[];
        if (bytes != null && bytes.Length != 64)
            return Compare(left, new LongLong(bytes));
        if (right is Guid)
            return Compare(left, new LongLong((Guid) right));
        throw new ArgumentException();
    }
    public static int Compare(LongLong left, LongLong right)
    {
        return left.B64.CompareTo(right.B64);
    }
    public int CompareTo(LongLong value)
    {
        return Compare(this, value);
    }
    public static implicit operator LongLong(bool value)
    {
        return new LongLong(value);
    }
    public static implicit operator LongLong(byte value)
    {
        return new LongLong(value);
    }
    public static implicit operator LongLong(char value)
    {
        return new LongLong(value);
    }
    public static explicit operator LongLong(decimal value)
    {
        return new LongLong(value);
    }
    public static explicit operator LongLong(double value)
    {
        return new LongLong(value);
    }
    public static implicit operator LongLong(short value)
    {
        return new LongLong(value);
    }
    public static implicit operator LongLong(int value)
    {
        return new LongLong(value);
    }
    public static implicit operator LongLong(long value)
    {
        return new LongLong(value);
    }
    public static implicit operator LongLong(sbyte value)
    {
        return new LongLong(value);
    }
    public static explicit operator LongLong(float value)
    {
        return new LongLong(value);
    }
    public static implicit operator LongLong(ushort value)
    {
        return new LongLong(value);
    }
    public static implicit operator LongLong(uint value)
    {
        return new LongLong(value);
    }
    public static implicit operator LongLong(ulong value)
    {
        return new LongLong(value);
    }
    public static implicit operator LongLong(UInt128 value)
    {
        return new LongLong(value);
    }
    public static explicit operator bool(LongLong value)
    {
        return (byte) value.B64 != 0;
    }
    public static explicit operator byte(LongLong value)
    {
        return (byte) value.B64;
    }
    public static explicit operator char(LongLong value)
    {
        return (char) (ushort) value.B64;
    }
    public static explicit operator decimal(LongLong value)
    {
        return new decimal((int) (value.B64 & 0xFFFFFFFF), 0, 0, false, 0);
    }
    public static explicit operator double(LongLong value)
    {
        var nfi = CultureInfo.InvariantCulture.NumberFormat;
        if (!double.TryParse(value.ToString(nfi), NumberStyles.Number, nfi, out var d))
            throw new OverflowException();
        return d;
    }
    public static explicit operator float(LongLong value)
    {
        var nfi = CultureInfo.InvariantCulture.NumberFormat;
        if (!float.TryParse(value.ToString(nfi), NumberStyles.Number, nfi, out var f))
            throw new OverflowException();
        return f;
    }
    public static explicit operator short(LongLong value)
    {
        return (short) (int) value.B64;
    }
    public static explicit operator int(LongLong value)
    {
        return (int) value.B64;
    }
    public static explicit operator long(LongLong value)
    {
        return (long) value.B64;
    }
    public static explicit operator uint(LongLong value)
    {
        return (uint) value.B64;
    }
    public static explicit operator ushort(LongLong value)
    {
        return (ushort) value.B64;
    }
    public static explicit operator ulong(LongLong value)
    {
        return value.B64;
    }
    public static explicit operator BigInteger(LongLong value)
    {
        return new BigInteger(value.ToByteArray().Concat(new byte[] {0}).ToArray());
    }
    public static explicit operator UInt128(LongLong value)
    {
        return new UInt128(value.B64);
    }
    public static bool operator >(LongLong left, LongLong right)
    {
        return Compare(left, right) > 0;
    }
    public static bool operator <(LongLong left, LongLong right)
    {
        return Compare(left, right) < 0;
    }
    public static bool operator >=(LongLong left, LongLong right)
    {
        return Compare(left, right) >= 0;
    }
    public static bool operator <=(LongLong left, LongLong right)
    {
        return Compare(left, right) <= 0;
    }
    public static bool operator !=(LongLong left, LongLong right)
    {
        return Compare(left, right) != 0;
    }
    public static bool operator ==(LongLong left, LongLong right)
    {
        return Compare(left, right) == 0;
    }
    public static LongLong operator +(LongLong value)
    {
        return value;
    }
    public static LongLong operator ~(LongLong value)
    {
        return -(value + One);
    }
    public static LongLong operator -(LongLong value)
    {
        return Negate(value);
    }
    public static LongLong operator ++(LongLong value)
    {
        return value + 1;
    }
    public static LongLong operator --(LongLong value)
    {
        return value - 1;
    }
    public static LongLong Negate(LongLong value)
    {
        return new LongLong(~value.B64) + 1;
    }
    public static LongLong operator +(LongLong left, LongLong right)
    {
        left.B64 += right.B64;
        return left;
    }
    public static LongLong operator -(LongLong left, LongLong right)
    {
        return left + -right;
    }
    public static LongLong Add(LongLong left, LongLong right)
    {
        return left + right;
    }
    public static LongLong Subtract(LongLong left, LongLong right)
    {
        return left - right;
    }
    public static LongLong Divide(LongLong dividend, LongLong divisor)
    {
        return DivRem(dividend, divisor, out var integer);
    }
    public static LongLong DivRem(LongLong dividend, LongLong divisor, out LongLong remainder)
    {
        if (divisor == 0)
            throw new DivideByZeroException();
        DivRem(dividend.ToUIn32Array(), divisor.ToUIn32Array(), out var quotient, out var rem);
        remainder = new LongLong(rem);
        return new LongLong(quotient);
    }
    private static void DivRem(uint[] dividend, uint[] divisor, out uint[] quotient, out uint[] remainder)
    {
        const ulong hiBit       = 0x100000000;
        var         divisorLen  = GetLength(divisor);
        var         dividendLen = GetLength(dividend);
        if (divisorLen <= 1)
        {
            ulong rem = 0;
            var   div = divisor[0];
            quotient  = new uint[dividendLen];
            remainder = new uint[1];
            for (var i = dividendLen - 1; i >= 0; i--)
            {
                rem *= hiBit;
                rem += dividend[i];
                var q = rem / div;
                rem         -= q * div;
                quotient[i] =  (uint) q;
            }
            remainder[0] = (uint) rem;
            return;
        }
        if (dividendLen >= divisorLen)
        {
            var shift        = GetNormalizeShift(divisor[divisorLen - 1]);
            var normDividend = new uint[dividendLen + 1];
            var normDivisor  = new uint[divisorLen];
            Normalize(dividend, dividendLen, normDividend, shift);
            Normalize(divisor,  divisorLen,  normDivisor,  shift);
            quotient = new uint[dividendLen - divisorLen + 1];
            for (var j = dividendLen - divisorLen; j >= 0; j--)
            {
                var dx = hiBit * normDividend[j + divisorLen] + normDividend[j + divisorLen - 1];
                var qj = dx / normDivisor[divisorLen                                        - 1];
                dx -= qj * normDivisor[divisorLen - 1];
                do
                {
                    if (qj < hiBit && qj * normDivisor[divisorLen - 2] <= dx * hiBit + normDividend[j + divisorLen - 2])
                        break;
                    qj -= 1L;
                    dx += normDivisor[divisorLen - 1];
                } while (dx < hiBit);
                ulong di = 0;
                ulong dj;
                var   index = 0;
                while (index < divisorLen)
                {
                    var dqj = normDivisor[index] * qj;
                    dj                      = normDividend[index + j] - (uint) dqj - di;
                    normDividend[index + j] = (uint) dj;
                    dqj                     = dqj >> 32;
                    dj                      = dj  >> 32;
                    di                      = dqj - dj;
                    index++;
                }
                dj                           = normDividend[j + divisorLen] - di;
                normDividend[j + divisorLen] = (uint) dj;
                quotient[j]                  = (uint) qj;
                if (dj < 0)
                {
                    quotient[j]--;
                    ulong sum = 0;
                    for (index = 0; index < divisorLen; index++)
                    {
                        sum                     = normDivisor[index] + normDividend[j + index] + sum;
                        normDividend[j + index] = (uint) sum;
                        sum                     = sum >> 32;
                    }
                    sum += normDividend[j + divisorLen];
                    normDividend[j        + divisorLen] = (uint) sum;
                }
            }
            remainder = Unnormalize(normDividend, shift);
            return;
        }
        quotient  = new uint[0];
        remainder = dividend;
    }
    private static int GetLength(uint[] uints)
    {
        var index = uints.Length - 1;
        while (index >= 0 && uints[index] == 0)
            index--;
        return index + 1;
    }
    private static int GetNormalizeShift(uint ui)
    {
        var shift = 0;
        if ((ui & 0xffff0000) == 0)
        {
            ui    =  ui << 16;
            shift += 16;
        }
        if ((ui & 0xff000000) == 0)
        {
            ui    =  ui << 8;
            shift += 8;
        }
        if ((ui & 0xf0000000) == 0)
        {
            ui    =  ui << 4;
            shift += 4;
        }
        if ((ui & 0xc0000000) == 0)
        {
            ui    =  ui << 2;
            shift += 2;
        }
        if ((ui & 0x80000000) == 0)
            shift++;
        return shift;
    }
    private static uint[] Unnormalize(uint[] normalized, int shift)
    {
        var len          = GetLength(normalized);
        var unnormalized = new uint[len];
        if (shift > 0)
        {
            var  rshift = 32 - shift;
            uint r      = 0;
            for (var i = len - 1; i >= 0; i--)
            {
                unnormalized[i] = (normalized[i] >> shift) | r;
                r               = normalized[i] << rshift;
            }
        }
        else
        {
            for (var j = 0; j < len; j++)
                unnormalized[j] = normalized[j];
        }
        return unnormalized;
    }
    private static void Normalize(uint[] unormalized, int len, uint[] normalized, int shift)
    {
        int  i;
        uint n = 0;
        if (shift > 0)
        {
            var rShift = 32 - shift;
            for (i = 0; i < len; i++)
            {
                normalized[i] = (unormalized[i] << shift) | n;
                n             = unormalized[i] >> rShift;
            }
        }
        else
        {
            i = 0;
            while (i < len)
            {
                normalized[i] = unormalized[i];
                i++;
            }
        }
        while (i < normalized.Length)
            normalized[i++] = 0;
        if (n != 0)
            normalized[len] = n;
    }
    public static LongLong Remainder(LongLong dividend, LongLong divisor)
    {
        DivRem(dividend, divisor, out var remainder);
        return remainder;
    }
    public static LongLong Max(LongLong left, LongLong right)
    {
        return left.CompareTo(right) < 0 ? right : left;
    }
    public static LongLong Min(LongLong left, LongLong right)
    {
        return left.CompareTo(right) <= 0 ? left : right;
    }
    public static int GetBitWidth(LongLong n)
    {
        LongLong bitWidth = 1;
        var      v        = n;
        while ((v >>= 1) > 0)
            bitWidth++;
        if (bitWidth < 8)
            bitWidth = 8;
        while (bitWidth % 8 != 0)
            bitWidth++;
        return (int) bitWidth;
    }
    public static LongLong operator %(LongLong dividend, LongLong divisor)
    {
        return Remainder(dividend, divisor);
    }
    public static LongLong operator /(LongLong dividend, LongLong divisor)
    {
        return Divide(dividend, divisor);
    }
    public ulong[] ToUIn64Array()
    {
        return new[] {B64};
    }
    public ulong[] ToUIn64Array(byte[] value)
    {
        if (value == null)
            throw new Exception("Value cannot be null.");
        var al = value.Length / 8;
        if (al * 8 != value.Length)
            al++;
        var arr = new ulong[al];
        Buffer.BlockCopy(value, 0, arr, 0, value.Length);
        return arr;
    }
    public uint[] ToUIn32Array(byte[] value)
    {
        if (value == null)
            throw new Exception("Value cannot be null.");
        var al = value.Length / 4;
        if (al * 4 != value.Length)
            al++;
        var arr = new uint[al];
        Buffer.BlockCopy(value, 0, arr, 0, value.Length);
        return arr;
    }
    public uint[] ToUIn32Array(ulong[] value)
    {
        if (value == null)
            throw new Exception("Value cannot be null.");
        var arr = new uint[value.Length * 2];
        Buffer.BlockCopy(value, 0, arr, 0, value.Length);
        return arr;
    }
    public ulong[] ToUIn64Array(uint[] value)
    {
        if (value == null)
            throw new Exception("Value cannot be null.");
        var al = value.Length / 2;
        if (al * 2 != value.Length)
            al++;
        var arr = new ulong[al];
        Buffer.BlockCopy(value, 0, arr, 0, value.Length);
        return arr;
    }
    public uint[] ToUIn32Array()
    {
        var uia = new uint[16];
        var ula = ToUIn64Array();
        Buffer.BlockCopy(ula, 0, uia, 0, 64);
        return uia;
    }
    public byte[] ToByteArray()
    {
        var ba  = new byte[64];
        var ula = ToUIn64Array();
        Buffer.BlockCopy(ula, 0, ba, 0, 64);
        return ba;
    }
    public static LongLong Multiply(LongLong left, LongLong right)
    {
        var xInts   = left.ToUIn32Array();
        var yInts   = right.ToUIn32Array();
        var mulInts = new uint[Math.Max(xInts.Length, yInts.Length) << 1];
        for (var i = 0; i < xInts.Length; i++)
        {
            var   index     = i;
            ulong remainder = 0;
            foreach (var yi in yInts)
            {
                remainder        = remainder + (ulong) xInts[i] * yi + mulInts[index];
                mulInts[index++] = (uint) remainder;
                remainder        = remainder >> 32;
            }
            while (remainder != 0)
            {
                remainder        += mulInts[index];
                mulInts[index++] =  (uint) remainder;
                remainder        =  remainder >> 32;
            }
        }
        return new LongLong(mulInts);
    }
    public static LongLong operator *(LongLong left, LongLong right)
    {
        return Multiply(left, right);
    }
    public static LongLong operator >>(LongLong value, int shift)
    {
        var values      = value.ToUIn64Array();
        var valueLength = sizeof(ulong) * 8;
        var length      = values.Length;
        shift = shift % (length * valueLength);
        var shiftOffset = shift / valueLength;
        var bshift      = shift % valueLength;
        var shifted     = new ulong[length];
        for (var i = 0; i < length; i++)
        {
            var ishift = i - shiftOffset;
            if (ishift < 0)
                continue;
            shifted[ishift] |= values[i] >> bshift;
            if (bshift > 0 && i + 1 < length)
                shifted[ishift] |= values[i + 1] << (valueLength - bshift);
        }
        return new LongLong(shifted[0]);
    }
    public static LongLong operator <<(LongLong value, int shift)
    {
        var values      = value.ToUIn64Array();
        var valueLength = sizeof(ulong) * 8;
        var length      = values.Length;
        shift %= length * valueLength;
        var shiftOffset = shift / valueLength;
        var bshift      = shift % valueLength;
        var shifted     = new ulong[length];
        for (var i = 0; i < length; i++)
        {
            var ishift = i + shiftOffset;
            if (ishift >= length)
                continue;
            shifted[ishift] |= values[i] << bshift;
            if (bshift > 0 && i - 1 >= 0)
                shifted[ishift] |= values[i - 1] >> (valueLength - bshift);
        }
        return new LongLong(shifted[0]);
    }
    public static LongLong operator |(LongLong left, LongLong right)
    {
        if (left == 0)
            return right;
        if (right == 0)
            return left;
        var x = left.ToUIn32Array();
        var y = right.ToUIn32Array();
        var z = new uint[Math.Max(x.Length, y.Length)];
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < x.Length ? x[i] : 0u;
            var yu = i < y.Length ? y[i] : 0u;
            z[i] = xu | yu;
        }
        return new LongLong(z);
    }
    public static LongLong operator ^(LongLong left, LongLong right)
    {
        var x = left.ToUIn32Array();
        var y = right.ToUIn32Array();
        var z = new uint[Math.Max(x.Length, y.Length)];
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < x.Length ? x[i] : 0u;
            var yu = i < y.Length ? y[i] : 0u;
            z[i] = xu ^ yu;
        }
        return new LongLong(z);
    }
    public static LongLong operator &(LongLong left, LongLong right)
    {
        if (left == 0 || right == 0)
            return Zero;
        var x = left.ToUIn32Array();
        var y = right.ToUIn32Array();
        var z = new uint[Math.Max(x.Length, y.Length)];
        for (var i = 0; i < z.Length; i++)
        {
            var xu = i < x.Length ? x[i] : 0u;
            var yu = i < y.Length ? y[i] : 0u;
            z[i] = xu & yu;
        }
        return new LongLong(z);
    }
    private class LongLongConverter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
        }
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (value != null)
                if (TryParse($"{value}", out var i))
                    return i;
            return new LongLong();
        }
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            return destinationType == typeof(string) || base.CanConvertTo(context, destinationType);
        }
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            return destinationType == typeof(string) ? $"{value}" : base.ConvertTo(context, culture, value, destinationType);
        }
    }
}

ZOB64.cs

Example Zobrist Hashing 64-Bit

using System;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
/// <summary>
///     
///     https://en.wikipedia.org/wiki/Zobrist_hashing
///    
/// </summary>
public class ZOB64 : HashAlgorithm
{
    private readonly ulong      starthash = 0x391615744853B307;
    private          ulong[]    _table;
    private          ulong      hash;
    private          uint       hash32;
    private          ZOB32State zhs;
    public ZOB64()
    {
        hash = starthash;
        BuildTable(0x7965CBDDD4A9E7AF);
    }
    public override int HashSize => 64;
    public override void Initialize()
    {
        hash = starthash;
    }
    protected override void HashCore(byte[] bytes, int ibStart, int cbSize)
    {
        Hash64(bytes, ibStart, cbSize);
    }
    private static ulong RotateLeft(ulong value, int count)
    {
        return(value << count) | (value >> (64 - count % 64));
    }
    private unsafe void Hash64(byte[] bytes, int ibStart, int cbSize)
    {
        if(bytes == null)
            return;
        if(ibStart >= bytes.Length || cbSize > bytes.Length)
            return;
        var i = 1;
        fixed(byte* pb = bytes)
        {
            var nb = pb + ibStart;
            while(cbSize >= 1)
            {
                hash   ^= RotateLeft(_table[*nb], i++);
                nb     += 1;
                cbSize -= 1;
            }
        }
    }
    protected override byte[] HashFinal()
    {
        zhs.hash64 = hash;
        hash32     = zhs.hi ^ zhs.lo;
        return hash.GetBytes();
    }
    public void BuildTable(ulong seed)
    {
        var s1   = (int) seed;
        var s2   = (int) (seed >> 32);
        var rnd  = new Random(s1);
        var rnd1 = new Random(s2);
        var tt   = new DynHashSet32<ulong>();
        _table = new ulong[256];
        var u = new ZOB32State();
        for(var i = 0; i < 256; i++)
        {
            ulong v;
            do
            {
                u.hi = (uint) rnd.Next();
                u.lo = (uint) rnd1.Next();
                v    = u.hash64;
            } while(tt.Contains(v));
            tt.Add(v);
            _table[i] = v;
        }
    }
    [StructLayout(LayoutKind.Explicit)]
    public struct ZOB32State
    {
        [FieldOffset(0)] public ulong hash64;
        [FieldOffset(0)] public uint  lo;
        [FieldOffset(4)] public uint  hi;
    }
}

Mapping160BitTo64BitHash.cs

Maps a 160-Bit Hash Into a 64-Bit Space

using System.Security.Cryptography;
/// <summary>
///     Pros: ~no Collisions within long bit space ~(9,223,372,036,854,775,807)
///     Cons: Maintains a TinyDictionary(byte[],byte[]), non-deterministic across application or
///     method domains
///     Cannot Transform or reuse.
/// </summary>
public class Mapping160BitTo64BitHash : HashAlgorithm
{
    public readonly  TinyDictionary<byte[], byte[]> map = new TinyDictionary<byte[], byte[]>(101, new ArrayComparer());
    private          byte[]                         h160;
    private readonly SHA1Managed                    hasher = new SHA1Managed();
    public override  int                            HashSize => 64;
    public override void Initialize()
    {
    }
    /// <inheritdoc />
    /// <summary>
    ///     Compute the 64 Bit hash value and add it and the original array to the map to create a unique position within the
    ///     TinyDictionary.
    /// </summary>
    protected override void HashCore(byte[] bytes, int ibStart, int cbSize)
    {
        h160 = hasher.ComputeHash(bytes, ibStart, cbSize);
        map.Add(h160, bytes);
    }
    /// <inheritdoc />
    /// <summary>
    ///     Return the unique position within the TinyDictionary as the hash value (index).
    /// </summary>
    protected override byte[] HashFinal()
    {
        HashValue = (byte[])map.FindKeyIndex(h160).GetBytes().Clone();
        return HashValue;
    }
}

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