Mersenne Twister (MT19937): Period, Reproducibility, and Security Limits
DDEVELOPER
DeveloperPublished: 12 min read

Mersenne Twister (MT19937): Period, Reproducibility, and Security Limits

Mersenne Twister (MT19937) is a pseudorandom number generator described in a 1998 paper by Makoto Matsumoto and Takuji Nishimura. Its long period and reproducibility are useful for simulations, but it is unsuitable for passwords or secret tokens. This guide separates period, state, and equidistribution, then demonstrates the sequence with runnable JavaScript. It does not imply that NanToo’s dice or draw tools use MT.

Japanese original published: 2026-04-28

The Japanese research behind the 1998 paper

Makoto Matsumoto and Takuji Nishimura introduced Mersenne Twister in their 1998 paper. The author manuscript lists Keio University and the Max Planck Institute for Mathematics for Matsumoto, and Keio University for Nishimura. Its present-day hosting on a Hiroshima University domain does not establish that the research originated there.

The authors date development to 1996–1997 and the improved initialization code to 2002. The original algorithm and the later initialization procedure are distinct. “Mersenne” refers to the Mersenne prime associated with the period; “Twister” refers to its twisted generalized feedback shift register design.

Physical entropy and pseudorandom generation are different layers

A pseudorandom number generator (PRNG) determines its next state and output from its current state. Fix the algorithm, initialization procedure, seed, and call order, and you can reproduce the sequence. The same seed alone does not guarantee matching results across languages or APIs.

Entropy obtained from physical noise and the generator that expands seeded state into outputs are different layers. A cryptographically secure PRNG (CSPRNG) also includes deterministic operations, but suitable seeding and design make its outputs difficult to predict. Determinism does not disqualify every generator from cryptographic use; MT19937 lacks the required cryptographic design.

Intel’s RDRAND instruction returns the output of a deterministic random bit generator (DRBG), not unprocessed physical noise. CPU and operating-system random APIs should not all be described as returning raw “true randomness.”

Period, stored state, and seed space

Scroll horizontally if the table does not fit.

QuantityMeaning for MT19937
Period219937−1 for a nonzero effective state: approximately 4.3 × 106001
Stored state representation624 words of 32 bits: 2,496 bytes, excluding the index and other bookkeeping
State dimension of the recurrence624 × 32 − 31 = 19,937 bits
One 32-bit seedAt most 232 initialization inputs, not one input for every position in the period

The period measures how long the sequence runs before repeating. It does not mean that a short seed can select every possible initial state, nor does it prove that adjacent outputs are independent. APIs with a 32-bit seed, such as PHP’s Mt19937, have a limited seed space despite the generator’s enormous period.

What 623-dimensional equidistribution guarantees

MT19937 is 623-dimensionally equidistributed at 32-bit precision. Group 623 consecutive full 32-bit outputs together and move the starting position through the entire period: every possible bit pattern occurs equally often, except that the all-zero tuple occurs once fewer. That exception is part of the original definition.

When outputs are truncated to v bits, the corresponding equidistribution dimension k(v) must be considered separately. Bit precision and dimension are different quantities.

This property does not promise equal counts in a short sample, success on every statistical test, or cryptographic unpredictability. It also differs from the conditional uniformity required of each index selection in a Fisher–Yates shuffle.

Twisting and tempering with 32-bit arithmetic

The state update joins the upper bit of one word to the lower 31 bits of the next. It uses a right shift, a conditional XOR, and an offset of 397 words. Tempering applies shifts and masked XOR operations to an output word. This is a reversible bit transformation, not encryption.

The educational example below uses the 2002 initialization procedure for a single 32-bit seed. Arithmetic wraps modulo 232. In JavaScript, Math.imul supplies the low 32 bits of multiplication, and >>> performs an unsigned right shift. The twist updates the array sequentially in place; after wrapping around, it also reads words that have already been updated. Replacing this with a separate array computed entirely from the old block changes the sequence.

function mt19937(seed) {
  if (!Number.isInteger(seed) || seed < 0 || seed > 0xffffffff) {
    throw new RangeError("Expected an integer seed from 0 to 2^32-1");
  }
  const state = new Uint32Array(624);
  state[0] = seed;
  for (let i = 1; i < 624; i++) {
    const previous = state[i - 1];
    state[i] = (Math.imul(1812433253, previous ^ (previous >>> 30)) + i) >>> 0;
  }
  let cursor = 624;
  return function nextUint32() {
    if (cursor === 624) {
      for (let i = 0; i < 624; i++) {
        const joined = (state[i] & 0x80000000) | (state[(i + 1) % 624] & 0x7fffffff);
        state[i] = (state[(i + 397) % 624] ^ (joined >>> 1) ^
          ((joined & 1) ? 0x9908b0df : 0)) >>> 0;
      }
      cursor = 0;
    }
    let value = state[cursor++];
    value ^= value >>> 11;
    value ^= (value << 7) & 0x9d2c5680;
    value ^= (value << 15) & 0xefc60000;
    return (value ^ (value >>> 18)) >>> 0;
  };
}
const next = mt19937(5489);
console.log(Array.from({ length: 5 }, () => next()));
// [3499211612, 581869302, 3890346734, 3586334585, 545404204]

The state is twisted before the first output and again after each block of 624 outputs. Each generator has its own state array and returns one unsigned 32-bit integer per call. This example is for learning: it is neither a cryptographic generator nor a universal match for every language’s seeding rules.

What to record for reproducibility

Record the generator, library and version, initialization procedure, seed or saved state, call order, and conversion into the desired range or distribution. An integer, a floating-point value, and a normally distributed value need not consume the same number of internal outputs.

Do not expect seed 5489 in this example to match Python’s random.seed(5489): their initialization procedures differ. Giving every parallel worker the same seed does not create independent streams. Check the library’s documented stream-splitting or spawning behavior.

Mapping an unsigned 32-bit output to an integer range by taking its remainder modulo n introduces bias when n does not divide 232. Selecting MT does not remove that bias. Evaluate the generator and the range-conversion method separately.

Where MT appears in language libraries

Scroll horizontally if the table does not fit.

EnvironmentAPI and limitations
Pythonrandom.Random uses MT; SystemRandom is different. Use secrets for secret values.
C++std::mt19937 explicitly selects the 32-bit engine. Do not assume default_random_engine selects MT.
PHPmt_rand and Random\Engine\Mt19937. Check initialization and compatibility modes for behavior before PHP 7.1.
RThe default RNGkind is Mersenne-Twister. Conversion settings such as sample.kind also affect reproducibility.
RubyRandom uses a modified MT. Do not assume seed compatibility with the reference C implementation.
MATLABThe factory default on the client is twister. Check changed settings, parallel workers, and GPU generators separately.
NumPyRandomState uses legacy MT. Generator supports different bit generators; default_rng currently defaults to PCG64.

Widespread adoption does not establish that an algorithm is best for every task. Historical descriptions also do not justify claims about every current Excel version or an undocumented implementation.

Why MT is unsuitable for secrets

MT19937 is not cryptographically secure. Its state transition is linear and tempering is reversible, so a recovered state predicts later outputs. For example, 624 consecutive full 32-bit output words aligned with a state-update block allow the state to be reconstructed by reversing tempering.

This is not an unconditional claim that any 624 observations always suffice. Bounded integers, floating-point values assembled from multiple words, missing outputs, and intervening calls change what an observer sees. None of these transformations establishes that MT is secure.

For passwords, secret tokens, and keys, use an appropriate cryptographic API, such as browser crypto.getRandomValues(), Node.js crypto.randomBytes(), Python’s secrets, or PHP’s random_bytes(). Follow the protocol’s requirements for nonces: uniqueness and unpredictability are distinct properties, and MT does not automatically provide both.

Web Crypto requires cryptographically strong random values without prescribing a specific internal generator. Silently falling back to Math.random() after a failure breaks the security requirement for secret values.

Comparing alternatives without a universal ranking

SFMT is an MT-family generator designed with SIMD in mind. PCG and xoshiro families make different design choices. They cannot meaningfully be ranked as a single line of successors.

Compare the target CPU, compiler, integer width, distribution conversion, parallel streams, statistical tests, reproducibility, and security requirements. A speed ratio without those conditions is not useful. Replacing MT with a faster noncryptographic PRNG does not provide cryptographic security.

Randomness in NanToo’s Japanese tools

The following table describes how NanToo’s current Japanese tools generate and use random values.

Scroll horizontally if the table does not fit.

ToolRandom source and methodPurpose
Dice rollercrypto.getRandomValues() (CSPRNG)Match the stated random-source contract and avoid modulo bias
Coin flipcrypto.getRandomValues() (CSPRNG)Map one bit of a 32-bit value to heads or tails
Draw toolcrypto.getRandomValues(), rejection sampling, and Fisher–YatesMap 32-bit values to swap indices without modulo bias
Roulette toolcrypto.getRandomValues() and rejection samplingMap 32-bit values to candidate indices without modulo bias
Password generatorcrypto.getRandomValues() and rejection samplingSelect characters without modulo bias

These are implementation descriptions. Using Web Crypto alone does not establish equivalence to a physical draw, independently audited fairness, or compliance with legal requirements for lotteries or gambling.

A generator is not a shuffle or a probability model

The algorithm behind ECMAScript’s Math.random() is implementation-defined. Web Crypto does not specify MT either. The table above describes NanToo’s current Japanese tools; those tools do not use the educational MT implementation shown in this article.

A generator produces a sequence of values. Fisher–Yates uses selected values to rearrange a list. A probability calculator does something different again: it computes a mathematical distribution under assumptions such as independent, uniform dice. Theoretical results for sums of dice or rolling four dice and dropping the lowest are not MT-specific output guarantees.

Choose by purpose. Reproducible experiments need a PRNG whose configuration you can record. Secret values need an appropriate CSPRNG. Unbiased range selection needs a suitable mapping method as well.

References and sources

Editorial note

This article was prepared with AI assistance and reviewed by an editor before publication. It may still contain factual errors, interpretation mistakes, or outdated information. Check the cited primary sources or official documentation before making an important decision.

Related articles