using System; using System.Security.Cryptography; namespace Lidgren.Network { /// /// Multiply With Carry random /// public class MWCRandom : NetRandom { /// /// Get global instance of MWCRandom /// public static new readonly MWCRandom Instance = new MWCRandom(); private uint m_w, m_z; /// /// Constructor with randomized seed /// public MWCRandom() { Initialize(NetRandomSeed.GetUInt64()); } /// /// (Re)initialize this instance with provided 32 bit seed /// [CLSCompliant(false)] public override void Initialize(uint seed) { m_w = seed; m_z = seed * 16777619; } /// /// (Re)initialize this instance with provided 64 bit seed /// [CLSCompliant(false)] public void Initialize(ulong seed) { m_w = (uint)seed; m_z = (uint)(seed >> 32); } /// /// Generates a random value from UInt32.MinValue to UInt32.MaxValue, inclusively /// [CLSCompliant(false)] public override uint NextUInt32() { m_z = 36969 * (m_z & 65535) + (m_z >> 16); m_w = 18000 * (m_w & 65535) + (m_w >> 16); return ((m_z << 16) + m_w); } } /// /// Xor Shift based random /// public sealed class XorShiftRandom : NetRandom { /// /// Get global instance of XorShiftRandom /// public static new readonly XorShiftRandom Instance = new XorShiftRandom(); private const uint c_x = 123456789; private const uint c_y = 362436069; private const uint c_z = 521288629; private const uint c_w = 88675123; private uint m_x, m_y, m_z, m_w; /// /// Constructor with randomized seed /// public XorShiftRandom() { Initialize(NetRandomSeed.GetUInt64()); } /// /// Constructor with provided 64 bit seed /// [CLSCompliant(false)] public XorShiftRandom(ulong seed) { Initialize(seed); } /// /// (Re)initialize this instance with provided 32 bit seed /// [CLSCompliant(false)] public override void Initialize(uint seed) { m_x = (uint)seed; m_y = c_y; m_z = c_z; m_w = c_w; } /// /// (Re)initialize this instance with provided 64 bit seed /// [CLSCompliant(false)] public void Initialize(ulong seed) { m_x = (uint)seed; m_y = c_y; m_z = (uint)(seed << 32); m_w = c_w; } /// /// Generates a random value from UInt32.MinValue to UInt32.MaxValue, inclusively /// [CLSCompliant(false)] public override uint NextUInt32() { uint t = (m_x ^ (m_x << 11)); m_x = m_y; m_y = m_z; m_z = m_w; return (m_w = (m_w ^ (m_w >> 19)) ^ (t ^ (t >> 8))); } } /// /// Mersenne Twister based random /// public sealed class MersenneTwisterRandom : NetRandom { /// /// Get global instance of MersenneTwisterRandom /// public static new readonly MersenneTwisterRandom Instance = new MersenneTwisterRandom(); private const int N = 624; private const int M = 397; private const uint MATRIX_A = 0x9908b0dfU; private const uint UPPER_MASK = 0x80000000U; private const uint LOWER_MASK = 0x7fffffffU; private const uint TEMPER1 = 0x9d2c5680U; private const uint TEMPER2 = 0xefc60000U; private const int TEMPER3 = 11; private const int TEMPER4 = 7; private const int TEMPER5 = 15; private const int TEMPER6 = 18; private UInt32[] mt; private int mti; private UInt32[] mag01; private const double c_realUnitInt = 1.0 / ((double)int.MaxValue + 1.0); /// /// Constructor with randomized seed /// public MersenneTwisterRandom() { Initialize(NetRandomSeed.GetUInt32()); } /// /// Constructor with provided 32 bit seed /// [CLSCompliant(false)] public MersenneTwisterRandom(uint seed) { Initialize(seed); } /// /// (Re)initialize this instance with provided 32 bit seed /// [CLSCompliant(false)] public override void Initialize(uint seed) { mt = new UInt32[N]; mti = N + 1; mag01 = new UInt32[] { 0x0U, MATRIX_A }; mt[0] = seed; for (int i = 1; i < N; i++) mt[i] = (UInt32)(1812433253 * (mt[i - 1] ^ (mt[i - 1] >> 30)) + i); } /// /// Generates a random value from UInt32.MinValue to UInt32.MaxValue, inclusively /// [CLSCompliant(false)] public override uint NextUInt32() { UInt32 y; if (mti >= N) { GenRandAll(); mti = 0; } y = mt[mti++]; y ^= (y >> TEMPER3); y ^= (y << TEMPER4) & TEMPER1; y ^= (y << TEMPER5) & TEMPER2; y ^= (y >> TEMPER6); return y; } private void GenRandAll() { int kk = 1; UInt32 y; UInt32 p; y = mt[0] & UPPER_MASK; do { p = mt[kk]; mt[kk - 1] = mt[kk + (M - 1)] ^ ((y | (p & LOWER_MASK)) >> 1) ^ mag01[p & 1]; y = p & UPPER_MASK; } while (++kk < N - M + 1); do { p = mt[kk]; mt[kk - 1] = mt[kk + (M - N - 1)] ^ ((y | (p & LOWER_MASK)) >> 1) ^ mag01[p & 1]; y = p & UPPER_MASK; } while (++kk < N); p = mt[0]; mt[N - 1] = mt[M - 1] ^ ((y | (p & LOWER_MASK)) >> 1) ^ mag01[p & 1]; } } /// /// RNGCryptoServiceProvider based random; very slow but cryptographically safe /// public class CryptoRandom : NetRandom { /// /// Global instance of CryptoRandom /// public static new readonly CryptoRandom Instance = new CryptoRandom(); private RandomNumberGenerator m_rnd = new RNGCryptoServiceProvider(); /// /// Seed in CryptoRandom does not create deterministic sequences /// [CLSCompliant(false)] public override void Initialize(uint seed) { byte[] tmp = new byte[seed % 16]; m_rnd.GetBytes(tmp); // just prime it } /// /// Generates a random value from UInt32.MinValue to UInt32.MaxValue, inclusively /// [CLSCompliant(false)] public override uint NextUInt32() { var bytes = new byte[4]; m_rnd.GetBytes(bytes); return (uint)bytes[0] | (((uint)bytes[1]) << 8) | (((uint)bytes[2]) << 16) | (((uint)bytes[3]) << 24); } /// /// Fill the specified buffer with random values /// public override void NextBytes(byte[] buffer) { m_rnd.GetBytes(buffer); } /// /// Fills all bytes from offset to offset + length in buffer with random values /// public override void NextBytes(byte[] buffer, int offset, int length) { var bytes = new byte[length]; m_rnd.GetBytes(bytes); Array.Copy(bytes, 0, buffer, offset, length); } } }