# How to Use a Seed to Generate Random Numbers in JavaScript

Habdul Hazeez Feb 02, 2024

This article tackles how to use a seed to generate random numbers from PRNGs. Meanwhile, it’s a best practice to ensure that the seed for the PRNGs has high entropy.

Therefore, we’ll use a hashing function to generate the seed. Afterward, we pass the seed to the PRNG.

## Use a Seed and `SFC32` to Generate a Random Number

`SFC32` or Simple Fast Counter is a fast PRNG from `PractRand` (mostly in C), and it has an implementation in JavaScript with a 128-bit state, and it’s very fast. `SFC32` requires at least a single seed to generate the random number.

We’ll generate this seed using the hashing function, a JavaScript implementation of MurmurHash3, which requires an initial string to generate the seed. As a result, we pass in a string.

In the following code, we generate the seed and pass it to `SFC32` that returns the random number.

Code:

``````// Define the Murmur3Hash function
function MurmurHash3(string) {
let i = 0;
for (i, hash = 1779033703 ^ string.length; i < string.length; i++) {
let bitwise_xor_from_character = hash ^ string.charCodeAt(i);
hash = Math.imul(bitwise_xor_from_character, 3432918353);
hash = hash << 13 | hash >>> 19;
}
return () => {
// Return the hash that you can use as a seed
hash = Math.imul(hash ^ (hash >>> 16), 2246822507);
hash = Math.imul(hash ^ (hash >>> 13), 3266489909);
return (hash ^= hash >>> 16) >>> 0;
}
}

function SimpleFastCounter32(seed_1, seed_2, seed_3, seed_4) {
return () => {
seed_1 >>>= 0;
seed_2 >>>= 0;
seed_3 >>>= 0;
seed_4 >>>= 0;
let cast32 = (seed_1 + seed_2) | 0;
seed_1 = seed_2 ^ seed_2 >>> 9;
seed_2 = seed_3 + (seed_3 << 3) | 0;
seed_3 = (seed_3 << 21 | seed_3 >>> 11);
seed_4 = seed_4 + 1 | 0;
cast32 = cast32 + seed_4 | 0;
seed_3 = seed_3 + cast32 | 0;
return (cast32 >>> 0) / 4294967296;
}
}

let generate_seed = MurmurHash3('String for the Seed Key');
let random_number = SimpleFastCounter32(generate_seed(), generate_seed());
console.log(random_number());
console.log(random_number());
``````

Output:

``````0.837073584087193
0.3599331611767411
``````

## Use a Seed and `Mulberry32` to Generate a Random Number

`Mulberry32` is also a PRNG, though simpler in code structure than `SFC32`. Contrary to `SFC32`, which requires at least a seed.

We’ll use MurmurHash3 to generate the seed using a string. In the following example, we generate five random numbers using a for loop and `Mulberry32`.

Code:

``````// Define the Murmur3Hash function
function MurmurHash3(string) {
let i = 0;
for (i, hash = 1779033703 ^ string.length; i < string.length; i++) {
let bitwise_xor_from_character = hash ^ string.charCodeAt(i);
hash = Math.imul(bitwise_xor_from_character, 3432918353);
hash = hash << 13 | hash >>> 19;
}
return () => {
// Return the hash that you can use as a seed
hash = Math.imul(hash ^ (hash >>> 16), 2246822507);
hash = Math.imul(hash ^ (hash >>> 13), 3266489909);
return (hash ^= hash >>> 16) >>> 0;
}
}

function Mulberry32(string) {
return () => {
let for_bit32_mul = string += 0x6D2B79F5;
let cast32_one = for_bit32_mul ^ for_bit32_mul >>> 15;
let cast32_two = for_bit32_mul | 1;
for_bit32_mul = Math.imul(cast32_one, cast32_two);
for_bit32_mul ^= for_bit32_mul +
Math.imul(for_bit32_mul ^ for_bit32_mul >>> 7, for_bit32_mul | 61);
return ((for_bit32_mul ^ for_bit32_mul >>> 14) >>> 0) / 4294967296;
}
}

let generate_seed = MurmurHash3('String for the Seed Key');
let random_number = Mulberry32(generate_seed());

for (let i = 0; i < 5; i++) {
console.log(random_number());
}
``````

Output:

``````0.13532060221768916
0.8630009586922824
0.53870237339288
0.5237146227154881
0.8748106376733631
``````

## Use a Seed and `Xoshiro128**` to Generate a Random Number

Professor Vagna and Blackman developed the `Xoshiro128**` generator. The `xorshift128` is a family of the `Xorshift` PRNGs, and it’s the fastest PRNG.

Like `SFC32`, `Xoshiro128**` can take at least a seed before producing the random number. In the following snippet, we’ve created the required seed with MurmiurHash3.

Code:

``````// Define the Murmur3Hash function
function MurmurHash3(string) {
let i = 0;
for (i, hash = 1779033703 ^ string.length; i < string.length; i++) {
let bitwise_xor_from_character = hash ^ string.charCodeAt(i);
hash = Math.imul(bitwise_xor_from_character, 3432918353);
hash = hash << 13 | hash >>> 19;
}
return () => {
// Return the hash that you can use as a seed
hash = Math.imul(hash ^ (hash >>> 16), 2246822507);
hash = Math.imul(hash ^ (hash >>> 13), 3266489909);
return (hash ^= hash >>> 16) >>> 0;
}
}

function Xoshiro128_twostar(seed_1, seed_2, seed_3, seed_4) {
return () => {
let t = seed_2 << 9, y = seed_1 * 5;
y = (y << 7 | y >>> 25) * 9;
seed_3 ^= seed_1;
seed_4 ^= seed_2;
seed_2 ^= seed_3;
seed_1 ^= seed_4;
seed_3 ^= t;
seed_4 = seed_4 << 11 | seed_4 >>> 21;
return (y >>> 0) / 4294967296;
}
}

let generate_seed = MurmurHash3('String for the Seed Key');
let random_number = Xoshiro128_twostar(generate_seed(), generate_seed());
console.log(random_number());
``````

Output:

``````0.6150987280998379
``````

## Use a Seed and `JSF` to Generate a Random Number

Bob Jenkins created Jenkins Small Fast (JSF) generator, a fast generator. Though, it’s not fast when compared to `SFC32`.

When you observe the code of `JSF`, you’ll see similarities to `SFC32`. `JSF` can take more than a seed before producing a random number.

We generate ten random numbers with a seed and `JSF` in the next code.

Code:

``````// Define the Murmur3Hash function
function MurmurHash3(string) {
let i = 0;
for (i, hash = 1779033703 ^ string.length; i < string.length; i++) {
let bitwise_xor_from_character = hash ^ string.charCodeAt(i);
hash = Math.imul(bitwise_xor_from_character, 3432918353);
hash = hash << 13 | hash >>> 19;
}
return () => {
// Return the hash that you can use as a seed
hash = Math.imul(hash ^ (hash >>> 16), 2246822507);
hash = Math.imul(hash ^ (hash >>> 13), 3266489909);
return (hash ^= hash >>> 16) >>> 0;
}
}

function JenkinsSimpleFast32(seed_1, seed_2, seed_3, seed_4) {
return () => {
seed_1 |= 0;
seed_2 |= 0;
seed_3 |= 0;
seed_4 |= 0;
let t = seed_1 - (seed_2 << 27 | seed_2 >>> 5) | 0;
seed_1 = seed_2 ^ (seed_3 << 17 | seed_3 >>> 15);
seed_2 = seed_3 + seed_4 | 0;
seed_3 = seed_4 + t | 0;
seed_4 = seed_1 + t | 0;
return (seed_4 >>> 0) / 4294967296;
}
}

let generate_seed = MurmurHash3('String for the Seed Key');
let random_number = JenkinsSimpleFast32(generate_seed(), generate_seed());
for (let i = 0; i < 10; i++) {
console.log(random_number());
}
``````

Output:

``````0.513338076416403
0.4737987464759499
0.5743723993655294
0.4811882192734629
0.07753282226622105
0.11416710214689374
0.1270705321803689
0.15759771666489542
0.16906401910819113
0.6846413582097739
``````

## Use `seedrandom.js` to Generate a Random Number

`seedrandom.js` is a library by David Bau designed for seeded Random Number Generator (RNG), and it’s available on NPM and CDNJS. For this article, we’ll use CDNJS.

Keep the following in mind when using `Seedrandom.js`.

1. You initialize `seedrandom` using `new Math.seedrandom('seed key')`.
2. You can use the `quick()` function of `Seedrandom` to generate 32-bit of randomness.
3. The `int32()` function of Seedrandom.js returns a 32-bit signed integer.
4. Calling `seedrandom` with no arguments causes the creation of an auto-seeded ARC4-based PRNG. The auto-seeding uses some values like the accumulated local entropy.
5. `Seedrandom` can take an object as a second argument. This object is `{entropy: true}`, and the result is unpredictable.
6. Calling `Math.seedrandom` without the `new` keyword replaces the default `Math.random()`. The replacement is `new Math.seedrandom()`.

In this example, we’ve imported `seedrandom.js` from CDNJS. Afterward, we use it to generate a random number using a seed.

Code:

``````<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/3.0.5/seedrandom.min.js"></script>
<script>
let generate_random_number = new Math.seedrandom('Johnson');
console.log(generate_random_number());
</script>
</body>
``````

Output:

``````0.08103389758898699
``````

You can mix your seed with the accumulated entropy. You’ll need to pass `{entropy: true}` as the second argument of `seedrandom`.

Code:

``````<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/3.0.5/seedrandom.min.js"></script>
<script>
let generate_random_number = new Math.seedrandom('Antananarivo', { entropy: true });
for (let i = 0; i < 5; i++) {
console.log(generate_random_number());
}
</script>
</body>
``````

Output:

``````0.8478730572111559
0.963664252064149
0.6002684820777331
0.4026776455839767
0.7579996916288508
``````

In addition, `quick()` and `int32()` will return random 32-bit random numbers. The former will return a float, while the latter returns a signed integer.

Code:

``````<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/3.0.5/seedrandom.min.js"></script>
<script>
let generate_random_number = new Math.seedrandom('DavidBau');
console.log("With quick():", generate_random_number.quick());
console.log("With int32():", generate_random_number.int32());
</script>
</body>
``````

Output:

``````With quick(): 0.249648863915354
With int32(): -550219731
``````

Habdul Hazeez is a technical writer with amazing research skills. He can connect the dots, and make sense of data that are scattered across different media.