This page provide technical information and list of maximal triplets for xorshift generators, and it serve as an appendix for the main article titled Xorshift Generators and video documentary.
You can find a repository with all maximal triplets and characteristic polynomials here.
Xorshift Generators
- Proposed by Marsaglia in 2003 in “Xorshift RNG’s“
- Only 8, 16, 32, and 64 bits are typically natively possible on modern architectures
🟰 Shift matrices



xorshift (n bits, 2 shifts)
- Canonical tuples are maximal tuples where

- There are half as many canonical tuples as there are maximal tuples, because:
- If
is maximal, then
is also maximal
cannot be maximal
- If
- There are
possible tuples
uint32_t x;
uint32_t next(void)
{
x ^= x << a;
x ^= x >> b;
return x;
}
(1) ![]()
✏️ Correction
In his original paper, Marsaglia included (9, 5, 1) as a maximal triplet for xorshift32. That is likely a typo, as the actual maximal triplet is (9, 5, 14).
xorshift (n bits, 3 shifts)
- Canonical triplets are maximal triplets where

- There are half as many canonical triplets as there are maximal triplets, because:
- If
is maximal, then
is also maximal
cannot be maximal
- If
- There are
possible triplets - There are
possible triplets with 
uint32_t x;
uint32_t next(void)
{
x ^= x << a;
x ^= x >> b;
x ^= x << c;
return x;
}
(2) ![]()
🟰 Marsaglia’s xorshift32
Using Marsaglia’s triplet (13, 17, 5):


🟰 Marsaglia’s xorshift64
Using Marsaglia’s triplet (13, 7, 17):

| Bits | 32-bit blocks | All triplets | Maximal triplets | All canonical triplets (a<c) | Maximal canonical triplets |
|---|---|---|---|---|---|
| 8 | – | 343 | 24 | 147 | 12 |
| 16 | – | 3375 | 60 | 1575 | 30 |
| 32 | 1 | 29791 | 162 (13, 17, 5) xorshift32 | 14415 | 81 |
| 64 | 2 | 250047 | 550 (13, 7, 17) xorshift64 | 123039 | 275 |
| 96 | 3 | 857375 | 1022 | 424175 | 511 |
| 128 | 4 | 2048383 | 2144 | 1016127 | 1072 |
| 160 | 5 | 4019679 | 2636 | 1997199 | 1318 |
| 192 | 6 | 6967871 | 3360 | 3465695 | 1680 |
| 224 | 7 | 11089567 | 5354 | 5519919 | 2678 |
| 256 | 8 | 16581375 | 7594 | 8258175 | 3797 |
| 288 | 9 | 23639903 | 6884 | 11778767 | 3442 |
| 320 | 10 | 32461759 | 10118 | 16179999 | 5059 |
| 352 | 11 | 43243551 | 13402 | 21560175 | 6701 |
| 384 | 12 | 56181887 | 13156 | 28017599 | 6578 |
| 416 | 13 | 71473375 | 19416 | 35650575 | 9708 |
| 448 | 14 | 89314623 | 21190 | 44557407 | 10595 |
| 480 | 15 | 109902239 | 16538 | 54836399 | 8269 |
| 512 | 16 | 133432831 | 29738 | 66585855 | 14869 |
| 544 | 17 | 160103007 | 33436 | 79904079 | 16718 |
| 576 | 18 | 190109375 | 25902 | 94889375 | 12951 |
| 608 | 19 | 223648543 | 41102 | 111640047 | 20551 |
| 640 | 20 | 260917119 | 39042 | 130254399 | 19521 |
| 672 | 21 | 302111711 | 35440 | 150830735 | 17720 |
| 704 | 22 | 347428927 | 52028 | 173467359 | 26014 |
| 736 | 23 | 397065375 | 58682 | 198262575 | 29341 |
| 768 | 24 | 451217663 | 50264 | 225314687 | 25132 |
| 800 | 25 | 510082399 | 59688 | 254721999 | 29844 |
| 832 | 26 | 573856191 | 74532 | 286582815 | 37266 |
| 864 | 27 | 642735647 | 57036 | 320995439 | 28518 |
| 896 | 28 | 716917375 | 81136 | 358058175 | 40568 |
| 928 | 29 | 796597983 | 93096 | 397869327 | 46548 |
| 960 | 30 | 881974079 | 65074 | 440527199 | 32537 |
| 992 | 31 | 973242271 | 108502 | 486130095 | 54251 |
| 1024 | 32 | 1070599167 | 114630 | 534776319 | 57315 |
| 1280 | 40 | 2092240639 | 152820 | 1045302399 | 76410 |
| 2048 | 64 | 8577357823 | 452278 | 4286583807 | 226139 |
| 4096 | 128 | 68669157375 | 1790268 | 34326194175 | 895134 |
| 8192 | 256 | 549554511871 | ≤7143858 | 274743709695 | ≤3571929 |
A maximal triplet
is also maximal for the following 8 variants:
| A | Code | X |
|---|---|---|
x^= x << a; x ^= x >> b; x ^= x << c; | ||
| ||
| ||
| ||
| ||
| ||
| ||
|
📚 Properties of single-word xorshifts
- The three shifts cannot all be left shifts, or right shifts (Proposition 4.1)
- If
is a maximal triplet, it is also maximal for any of those 8 xorshift variants (Proposition 4.4), because all of their matrix forms are similar - If
is maximal, then
is also maximal:
(3) ![]()
This is because their respective transformation matrices are the transposes of each other. Transposing a matrix does not change its characteristic polynomial.
- A triplet of the kind
cannot be maximal:
(4) ![]()
This is true because the transition matrix would collapse into:
![]()
When a matrix is palindromic (i.e.:
), its characteristic polynomial becomes self-reciprocal (which means that its coefficients read exactly the same way forward and backwards). This makes it non-primitive, hence unable to achieve maximal period.
- For a triplet to be maximal,
,
,
, and
have to be setwise coprime:
(5) ![]()
This means they cannot share any prime factor. When
is a power of 2, its only prime factor is 2, and this property simply means that at least one among
,
, and
has to be odd (otherwise
).
❓ Open conjectures
The following properties are only conjectures, but likely true as were tested all values calculated so far:
- When
is even,
must be odd:
(6) ![]()
The proposed mechanism for this conjecture is that when
and
are even, then
for every odd
. If that happens, then all the odd-degree terms of the characteristic polynomial vanish (because they are linked directly to
through Newton’s identities). An even-degree term-only polynomial is a perfect square in characteristic 2, which makes it reducible, disqualifying it from being primitive.
and
cannot be both even at the same time- A canonical triplet cannot be maximal if
. This is likely because the shifts are “pushing out” too many bits, causing too much information to be lost, and collapsing the state.
📊 Statistical properties of maximal triplets
- Statistical bias torwards small a, small-tomedium b, mid-range c
- The density of canonical triplets scales like
, not
- Their distribution is not volumetric, and this suggests a lower-dimensional or heavily constrained subset.
- A possible (unconfirmed) explanation is that the number of monic degree-
polynomials is
, and the number of monic irreducible degree-
polynomials grows asymptotically to
. Therefore, a random degree-
polynomial is irreducibile with probability
. As a consequence, the expected number of maximal triplets among all triplets (which scale with
) would be be approximating
.
- Larger
correlates with smaller 
- Larger
correlates with smaller 
and
are positively correlated (beyond the canonical constraints
)
xorshift*
- Proposed by Vigna in 2004 in “An experimental exploration of Marsaglia’s xorshift generators, scrambled“
- A traditional xorshift on
bits, but the output is multiplied by a constant. This scrambles the bits enough to reduce linear artefacts
🟰 Vigna’s xorshift64*
Multiplicative constant
comes from Pierre L’Ecuyer’s research (“Tables of Linear Congruential Generators of different sizes and good lattice structure“)
#include <stdint.h>
uint64_t x;
uint64_t next(void)
{
x ^= x >> 12; // a
x ^= x << 25; // b
x ^= x >> 27; // c
return x * UINT64_C(2685821657736338717);
}

Marsaglia’s Companion Block Matrices
- Proposed by Marsaglia in 2003 in “Xorshift RNG’s“
- The
block structure mirrors a Frobenius companion matrix
(7) 
🟰 Marsaglia’s xorshift128 (32 bit)
❓ Unity Random: xorshift128 (32 bit)
Unity’s Random class implements a xorshift128 with 4 32-bit words (Unity Documentation: Random).
The C++ source code is not available, but a C# version has been reversed engineered and is available here.
public static uint x = 0, y = 0, z = 0, w = 0;
const uint MT19937 = 1812433253;
public static void InitSeed(int seed)
{
x = (uint)seed;
y = (uint)(MT19937 * x + 1);
z = (uint)(MT19937 * y + 1);
w = (uint)(MT19937 * z + 1);
}
public static void InitState(uint x, uint y, uint z, uint w)
{
XORShift128.x = x;
XORShift128.y = y;
XORShift128.z = z;
XORShift128.w = w;
}
public static uint XORShift()
{
uint t = x ^ (x << 11);
x = y; y = z; z = w;
return w = w ^ (w >> 19) ^ t ^ (t >> 8);
}
The seed is initialised using a technique inspired by the Mersenne Twister, using the MT19937 constant 1812433253.
| Bits | 16-bit blocks | Maximal triplets | 32-bit blocks | Maximal triplets | 64-bit blocks | Maximal triplets |
|---|---|---|---|---|---|---|
| 32 | 2 | 22 | – | – | – | – |
| 64 | 4 | 12 | 2 | 92 | – | – |
| 96 | 6 | 8 | 3 | 44 | – | – |
| 128 | 8 | 3 | 4 | 47 (11, 8, 19) xorshift128 | 2 | 349 |
| 160 | 10 | 5 | 5 | 25 (2, 1, 4) xorwow160 | – | – |
| 192 | 12 | 3 | 6 | 25 | 3 | 127 |
| 256 | 16 | 4 | 8 | 21 | 4 | 152 |
| 512 | 32 | 4 | 16 | 10 | 8 | 80 |
| 1024 | 64 | 0 | 32 | 5 | 16 | 24 |
| 2048 | 128 | 1 | 64 | 5 | 32 | 24 |
| 4096 | 256 | 2 | 128 | 0 | 64 | 13 |
| 8192 | 512 | 0 | 256 | ≤1 | 128 | ≤7 |
xorwow
- Proposed by Marsaglia in 2003 in “Xorshift RNG’s“
- Traditional companion xorshift, but the output state is scrambled using an additive counter (any odd constant works; Marsaglia chose 362437)
- Relies on the Weyl’s equidistribution theorem to distribute the bits over the period
- The additive counter expands the period by

🟰 NVIDIA cuRAND: xorwow160 (32 bit)
- NVIDIA cuRAND function implements a xorwow160 (CUDA Toolkit Documentation)
- The period is
. The official documentation indicates the period is “grater than
“ - Uses Marsaglia’s triplet (2, 1, 4), as well as its initial state (which can be found by setting the seed to zero)
uint32_t x = 123456789;
uint32_t y = 362436069;
uint32_t z = 521288629;
uint32_t w = 88675123;
uint32_t v = 886756453;
uint32_t d;
uint32_t next(void)
{
uint32_t t= x ^ (x >> 2); // A
x = y;
y = z;
z = w;
w = v;
v = v ^ (v << 4) ^ t ^ (t << 1); // C, B
return (d+=362437) + v; // Weyl sequence
}

xorshift+
- Proposed by Vigna in 2004 in “Further scramblings of Marsaglia’s xorshift generators“
- Traditional companion xorshift, but the output is the sum of the state variables. This scrambles the output bits enough to reduce linear artefacts.
- Does not need an additional parameter (like xorshift*)
🟰 Vigna’s xorshift128+ (64 bit)
uint64_t s[2];
uint64_t next(void)
{
uint64_t s1 = s[0];
const uint64_t s0 = s[1];
const uint64_t result = s0 + s1;
s[0] = s0;
s1 ^= s1 << 23; // a
s[1] = s1 ^ s0 ^ (s1 >> 18) ^ (s0 >> 5); // b, c
return result;
}

🟰 V8’s xorshift128+ (64 bit)
- Current implementation used by V8 JavaScript Engine.
- Adopted by Google in 2015 (“There’s Math.random(), and then there’s Math.random()“)
- Uses a different triplet compared to Vigna’s original xorshift128+ implementation
- Implementation code from random-number-generator.h:
uint64_t next (uint64_t* state0, uint64_t* state1) {
uint64_t s1 = *state0;
uint64_t s0 = *state1;
*state0 = s0;
s1 ^= s1 << 23; // a
s1 ^= s1 >> 17; // b
s1 ^= s0;
s1 ^= s0 >> 26; // c
*state1 = s1;
return s0 + s1;
}


Other techniques
🟰 Rotation matrix
The following techniques rely on left bitwise rotations. Vigna uses
in his paper; to avoid confusion with the right bitwise shifts, the letter
is used instead.
A left rotation can be implemented using two bitwise shifts:

From which we can extract the following expression:
![]()
Hence, the rotation matrix
is:
![]()
32 bit rotation:
static inline uint32_t rotl(const uint32_t x, int k) {
return (x << k) | (x >> (32 - k));
}
64 bit rotation:
static inline uint64_t rotl(const uint64_t x, int k) {
return (x << k) | (x >> (64 - k));
}
xoroshiro
- Proposed by Blackman & Vigna in 2018 “Scrambled Linear Pseudorandom Number Generators“
- Combines a rotation (ro-), a shift (-shi-), and a rotation (-ro)
- Cyclically updates two words of a larger state array
- Designed for parallelizability inside superscalar CPUs
(8) 
🟰 Vigna’s xoroshiro64 (32bit)
- Vigna suggests using (26, 9, 13) for both xoroshiro64* and xoroshiro64**
- The core of Java’s L32X64Mix is based on xoroshiro64 (26, 9, 13)
static uint32_t s[2];
uint32_t next(void) {
const uint32_t s0 = s[0];
uint32_t s1 = s[1];
const uint32_t result = rotl(s0 * 0x9E3779BB, 5) * 5; // starstar
const uint32_t result = s0 * 0x9E3779BB; // star
s1 ^= s0;
s[0] = rotl(s0, 26) ^ s1 ^ (s1 << 9); // a, b
s[1] = rotl(s1, 13); // c
return result;
}

🟰 Vigna’s xoroshiro128 (64bit)
- Vigna suggests using different triplets for different scrambled variants:
- (24, 16, 37): xoroshiro128**, xoroshiro128+
- (49, 21, 28): xoroshiro128++
- (55, 14, 36): xoroshiro128+ (older version from 2016)
static uint64_t s[2];
uint64_t next(void) {
const uint64_t s0 = s[0];
uint64_t s1 = s[1];
const uint64_t result = s0 + s1;
s1 ^= s0;
s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); // a, b
s[1] = rotl(s1, 37); // c
return result;
}

🟰 Vigna’s xoroshiro1024 (64 bit)
- Vigna suggests (25, 27, 36)
static int p;
static uint64_t s[16];
uint64_t next(void) {
const int q = p;
const uint64_t s0 = s[p = (p + 1) & 15];
uint64_t s15 = s[q];
const uint64_t result = rotl(s0 + s15, 23) + s15; // plusplus
const uint64_t result = rotl(s0 * 5, 7) * 9; // starstar
const uint64_t result = s0 * 0x9e3779b97f4a7c13; // star
s15 ^= s0;
s[q] = rotl(s0, 25) ^ s15 ^ (s15 << 27);
s[p] = rotl(s15, 36);
return result;
}

| Bits | 16-bit blocks | 32-bit blocks | 64-bit blocks |
|---|---|---|---|
| 64 | 26 | 250 (26, 9, 13) xoroshiro64** xoroshiro64* | – |
| 96 | 16 | 159 | – |
| 128 | 21 | 149 | 1000 (49, 21, 28) xoroshiro128++ (24, 16, 37) xoroshiro128** xoroshiro128+ |
| 192 | 2 | 55 | 670 |
| 256 | 7 | 59 | 491 |
| 512 | 3 | 41 | 261 |
| 1024 | 1 | 16 | 129 (25, 27, 36) xoroshiro1024++ xoroshiro1024** xoroshiro1024* |
| 2048 | 0 | 5 | 59 |
| 4096 | 0 | 6 | 37 |
| 8192 | 0 | ≤1 | ≤21 |
✏️ Corrections
Vigna reported 42 maximal triplets for xoroshiro2049 (64bit); the correct number is 59.
Vigna reported 25 maximal triplets for xoroshiro4096 (64 bit); the correct number is 37.
❓ Conjecture
It seems that for xoroshiro, when the word size is half the state size, the triplets are symmetrical (i.e.: if
is maximal, then
is also maximal).
This tested true for xoroshiro32 (16bit word), xoroshiro64 (32bit word), xoroshiro128 (64bit word).
xoshiro
- Proposed by Blackman & Vigna in 2018 “Scrambled Linear Pseudorandom Number Generators“
- Updates the entire state at each iteration (conversely to xoroshiro)
- Only two block matrices are defined:
and 
(9) 
(10) 
🟰 Vigna’s xoshiro128 (32 bit) (4×4)
static uint32_t s[4];
uint32_t next(void) {
const uint32_t result = rotl(s[0] + s[3], 7) + s[0]; // plusplus
const uint32_t result = rotl(s[1] * 5, 7) * 9; // starstart
const uint32_t result = s[0] + s[3]; // plus
const uint32_t t = s[1] << 9;
s[2] ^= s[0];
s[3] ^= s[1];
s[1] ^= s[2];
s[0] ^= s[3];
s[2] ^= t;
s[3] = rotl(s[3], 11);
return result;
}

🟰 Vigna’s xoshiro256 (64 bit) (4×4)
static uint64_t s[4];
uint64_t next(void) {
const uint64_t result = rotl(s[0] + s[3], 23) + s[0]; // plusplus
const uint64_t result = rotl(s[1] * 5, 7) * 9; // starstart
const uint64_t result = s[0] + s[3]; // plus
const uint64_t t = s[1] << 17;
s[2] ^= s[0];
s[3] ^= s[1];
s[1] ^= s[2];
s[0] ^= s[3];
s[2] ^= t;
s[3] = rotl(s[3], 45);
return result;
}

🟰 Vigna’s xoshiro512 (64 bit) (8×8)
static uint64_t s[8];
uint64_t next(void) {
const uint64_t result = rotl(s[0] + s[2], 17) + s[2]; // plusplus
const uint64_t result = rotl(s[1] * 5, 7) * 9; // startstar
const uint64_t result = s[0] + s[2]; // plus
const uint64_t t = s[1] << 11;
s[2] ^= s[0];
s[5] ^= s[1];
s[1] ^= s[2];
s[7] ^= s[3];
s[3] ^= s[4];
s[4] ^= s[5];
s[0] ^= s[6];
s[6] ^= s[7];
s[6] ^= t;
s[7] = rotl(s[7], 21);
return result;
}

| Size | 16-bit blocks | 32-bit blocks | 64-bit blocks |
|---|---|---|---|
| 4×4 | 1 (5, 11) | 1 (9, 11) xoshiro128++ xoshiro128** xoshiro128+ | 4 (17, 45) xoshiro256++ xoshiro256** xoshiro256+ |
| 8×8 | 0 | 0 | 4 (11, 21) xoshiro512++ xoshiro512** xoshiro512+ |
Bibliography
- [Marsaglia 2003] “Xorshift RNG’s”
- Introduces xorshifts generators
- Introduces companion matrices
- [Brent 2004] “Note on Marsaglia’s Xorshift Random Number Generators”
- Proof that xorshifts are LFSR
- Connection with characteristics/primitive polynomials
- [Panneton & L’Ecuyer 2005] “On the xorshift random number generators”
- Prove statistical weaknesses of xorshifts
- [Brent 2010] “Some long-period random number generators using shifts and xors”
- xorgens
- [Saito & Matshumoto 2014] “XORSHIFT-ADD (XSadd): A variant of XORSHIFT”
- XSadd
- Proposes xorshift with addition
- [Vigna 2014.1] “An experimental exploration of Marsaglia’s xorshift generators, scrambled”
- Introduces xorshift64*, xorshift1024*
- [Vigna 2014.2] “Further scramblings of Marsaglia’s xorshift generators”
- xorshift128+
- xorshift1024+
- [Bishoi & Maharana 2017] “Xorshift Random Number Generators From Primitive Polynomials”
- Shows a method to construct xorshifts from known primitive polynomials
- [Blackman & Vigna 2018] “Scrambled Linear Pseudorandom Number Generators”
- xoroshiro128+/xoroshiro128++/xoroshiro128/xoroshiro128* (64 bit)
- xoroshiro1024+/xoroshiro1024++/xoroshiro1024/xoroshiro1024* (64 bit)
- xoshiro256+/xoshiro256++/xoshiro256** (32 bit)
- xoshiro512+/xoshiro512++/xoshiro512** (64 bit)
- [Haramoto, Matsumoto, Saito 2019] “Unveiling patterns in xorshift128+ pseudorandom number generators”
- Reveal linear artefacts in xorshift128+




Leave a Reply