/**************************   mersenne.cpp   **********************************
* Author:        Agner Fog
* Date created:  2001
* Last modified: 2008-11-16
* Project:       randomc.h
* Platform:      Any C++
* Description:
* Random Number generator of type 'Mersenne Twister'
*
* This random number generator is described in the article by
* M. Matsumoto & T. Nishimura, in:
* ACM Transactions on Modeling and Computer Simulation,
* vol. 8, no. 1, 1998, pp. 3-30.
* Details on the initialization scheme can be found at
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
*
* Further documentation:
* The file ran-instructions.pdf contains further documentation and 
* instructions.
*
* Copyright 2001-2008 by Agner Fog. 
* GNU General Public License http://www.gnu.org/licenses/gpl.html
*******************************************************************************/

// Only the methods I need have been ported to C#...

namespace de4dot.code.deobfuscators.CodeWall.randomc {
	class CRandomMersenne {
		const int MERS_N = 624;
		const int MERS_M = 397;
		const int MERS_R = 31;
		const int MERS_U = 11;
		const int MERS_S = 7;
		const int MERS_T = 15;
		const int MERS_L = 18;
		const uint MERS_A = 0x9908B0DF;
		const uint MERS_B = 0x9D2C5680;
		const uint MERS_C = 0xEFC60000;

		uint[] mt = new uint[MERS_N];	// State vector
		int mti;						// Index into mt

		public CRandomMersenne() {
		}

		public CRandomMersenne(int seed) {
			RandomInit(seed);
		}

		void Init0(int seed) {
			// Seed generator
			const uint factor = 1812433253;
			mt[0] = (uint)seed;
			for (mti = 1; mti < MERS_N; mti++) {
				mt[mti] = (factor * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + (uint)mti);
			}
		}

		public void RandomInit(int seed) {
			// Initialize and seed
			Init0(seed);

			// Randomize some more
			for (int i = 0; i < 37; i++) BRandom();
		}

		static uint[] mag01 = new uint[2] { 0, MERS_A };
		public uint BRandom() {
			// Generate 32 random bits
			uint y;

			if (mti >= MERS_N) {
				// Generate MERS_N words at one time
				const uint LOWER_MASK = (1U << MERS_R) - 1;		// Lower MERS_R bits
				const uint UPPER_MASK = 0xFFFFFFFF << MERS_R;	// Upper (32 - MERS_R) bits

				int kk;
				for (kk = 0; kk < MERS_N - MERS_M; kk++) {
					y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
					mt[kk] = mt[kk + MERS_M] ^ (y >> 1) ^ mag01[y & 1];
				}

				for (; kk < MERS_N - 1; kk++) {
					y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
					mt[kk] = mt[kk + (MERS_M - MERS_N)] ^ (y >> 1) ^ mag01[y & 1];
				}

				y = (mt[MERS_N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
				mt[MERS_N - 1] = mt[MERS_M - 1] ^ (y >> 1) ^ mag01[y & 1];
				mti = 0;
			}
			y = mt[mti++];

			// Tempering (May be omitted):
			y ^= y >> MERS_U;
			y ^= (y << MERS_S) & MERS_B;
			y ^= (y << MERS_T) & MERS_C;
			y ^= y >> MERS_L;

			return y;
		}
	}
}
