Gathering detailed insights and metrics for pluggable-prng
Gathering detailed insights and metrics for pluggable-prng
Gathering detailed insights and metrics for pluggable-prng
Gathering detailed insights and metrics for pluggable-prng
An ES module with a class providing a Pseudo-random number generator which is "pluggable", meaning you can plug-in any PRNG algorithm. It's also "seedable" meaning that it can have a reproducible (deterministic) output based on its starting seed. The module includes plugins for some fast and good (insecure) PRNGs (Alea, Sfc32, Mulberry32, Pcg32), but also a much slower cryptographically secure PRNG which is using the Web Crypto API.
npm install pluggable-prng
Typescript
Module System
Min. Node Version
Node Version
NPM Version
73.6
Supply Chain
98.9
Quality
75.3
Maintenance
100
Vulnerability
99.6
License
JavaScript (99.63%)
Shell (0.37%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
MIT License
3 Stars
10 Commits
1 Watchers
1 Branches
2 Contributors
Updated on Mar 26, 2025
Latest Version
2.1.0
Package Id
pluggable-prng@2.1.0
Unpacked Size
64.09 kB
Size
17.58 kB
File Count
15
NPM Version
9.4.0
Node Version
19.6.0
Published on
Feb 06, 2023
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
1
An ES module providing a Pseudo-random number generator which is "pluggable", meaning you can plug-in any PRNG algorithm.
It's also "seedable" meaning that it can have a reproducible (deterministic) output based on its starting seed.
The module includes plugins for some fast and good (insecure) PRNGs (Alea, Sfc32, Mulberry32, Pcg32, IronWellons32 and WellonsTriple32).
But also a fast cryptographically secure PRNG which is using the Web Crypto API. It's compatible with Node.js, Deno and the browser.
If you find this useful then please consider helping me out (I'm jobless and sick). For more information visit my GitHub profile.
RandomGenerator
and SeedInitializer
(it auto-detects it).RandomGenerator
algorithm only needs to be able to output random Uint32
numbers, PluggablePRNG
will derive any numbers from them (signed, unsigned, single and double precision floats).constructor({[seed], RandomGenerator, [SeedInitializer]})
randomInteger([minOrMax], [max])
randomFloat32([minOrMax], [max])
randomFloat64([minOrMax], [max])
randomUint32()
randomBytes(count)
skipAhead(times)
reset()
exportState()
importState(state)
changeSeed(seed)
PluggablePRNG
RandomGenerator_Alea
RandomGenerator_Sfc32
RandomGenerator_Pcg32
RandomGenerator_Mulberry32
RandomGenerator_IronWellons32
RandomGenerator_WellonsTriple32
RandomGenerator_WebCrypto
SeedInitializer_Alea
SeedInitializer_Uint32
SeedInitializer_Uint64
SeedInitializer_WebCrypto
Xmur3
The hash function used in SeedInitializer_Uint32
.Mash
The hash function used in SeedInitializer_Alea
.Uint64
A 64-bit arithmetic library (faster than using BigInts).The 3 last exports in this list are used internally but was made available to anyone wanting to do whatever with them.
On my Intel® Core™ i5-10210U CPU @ 1.60GHz × 8
this is a typical result:
Iterations: 400000
Alea: 670ms
Mulberry32: 653ms
Sfc32: 927ms
Pcg32: 1532ms
Pcg32 (BigInt reference impl.): 2843ms
WebCrypto: 1363ms
IronWellons32: 666ms
WellonsTriple32: 684ms
1npm i pluggable-prng
1import {the, exports, you, want} from 'pluggable-prng'
Got problems using ES modules? Click here or read this.
1import {the, exports, you, want} from '/node_modules/pluggable-prng/source/pluggablePrng.js'
1import { 2 PluggablePRNG, 3 RandomGenerator_Alea, 4 SeedInitializer_Alea 5} from 'pluggable-prng' 6 7const log = console.log 8const wideNumber = new Intl.NumberFormat('fullwide', {maximumSignificantDigits: 21}) 9 10await prngDemoOutput(new PluggablePRNG({ 11 seed: 'Hello World', 12 RandomGenerator: RandomGenerator_Alea, 13 SeedInitializer: SeedInitializer_Alea 14})) 15 16async function prngDemoOutput(prng, iterations=5) { 17 await prng.readyPromise // if set (will be set when using async RandomGenerator or SeedInitializer) 18 log('\nrandomFloat32()') 19 for (let i=0; i<iterations; i++) { 20 let n = await prng.randomFloat32() // await is only needed if the RandomGenerator is async 21 log(wideNumber.format(n), n.toString(2)) 22 } 23 log('\nrandomFloat32(4)') 24 for (let i=0; i<iterations; i++) { 25 let n = await prng.randomFloat32(4) 26 log(wideNumber.format(n), n.toString(2)) 27 } 28 log('\nrandomFloat32(5,7)') 29 for (let i=0; i<iterations; i++) { 30 let n = await prng.randomFloat32(5,7) 31 log(wideNumber.format(n), n.toString(2)) 32 } 33 34 log('\nrandomFloat64()') 35 for (let i=0; i<iterations; i++) { 36 let n = await prng.randomFloat64() 37 log(wideNumber.format(n), n.toString(2)) 38 } 39 log('\nrandomFloat64(4)') 40 for (let i=0; i<iterations; i++) { 41 let n = await prng.randomFloat64(4) 42 log(wideNumber.format(n), n.toString(2)) 43 } 44 log('\nrandomFloat64(5,7)') 45 for (let i=0; i<iterations; i++) { 46 let n = await prng.randomFloat64(5,7) 47 log(wideNumber.format(n), n.toString(2)) 48 } 49 50 log('\nrandomInteger(-0xFFFF_FFFF, 0xFFFF_FFFF)') 51 for (let i=0; i<iterations; i++) { 52 let n = await prng.randomInteger(-0xFFFF_FFFF, 0xFFFF_FFFF) 53 log(n) 54 } 55 log('\nrandomInteger(0, 4)') 56 for (let i=0; i<iterations; i++) { 57 let n = await prng.randomInteger(0, 4) 58 log(n) 59 } 60 log('\nrandomInteger(0, Number.MAX_SAFE_INTEGER)') 61 log(integerToHex(2**53-1, 8), '== 53 bits all set (Number.MAX_SAFE_INTEGER)') 62 for (let i=0; i<iterations; i++) { 63 let n = await prng.randomInteger(0, Number.MAX_SAFE_INTEGER) 64 log(integerToHex(n, 8)) 65 } 66 log('\nrandomInteger(0, FF_FFFF_FFFF)') 67 for (let i=0; i<iterations; i++) { 68 let n = await prng.randomInteger(0, 0xFF_FFFF_FFFF) 69 log(integerToHex(n, 8)) 70 } 71 log('\nrandomInteger(FFFF_FFFF_0000, FFFF_FFFF_FFFF)') 72 for (let i=0; i<iterations; i++) { 73 let n = await prng.randomInteger(0xFFFF_FFFF_0000, 0xFFFF_FFFF_FFFF) 74 log(integerToHex(n, 8)) 75 } 76 log('\nrandomBytes(100)') 77 log(await prng.randomBytes(100)) 78} 79 80function integerToHex(integer, paddingByteSize = 4, grouping = 4) { 81 let hex = integer.toString(16).toUpperCase() 82 if (hex.length < paddingByteSize*2) 83 hex = '0'.repeat((paddingByteSize*2) - hex.length) + hex 84 if (grouping) { 85 let result = '' 86 if (hex.length % grouping) result += hex.slice(0, hex.length % grouping) + '_' 87 for (let i=hex.length % grouping; i<hex.length; i+=grouping) { 88 result += hex.slice(i, i+grouping) + '_' 89 } 90 hex = result.slice(0, -1) 91 } 92 return hex 93}
randomFloat32()
0.40236979722976685 0.011001110000000110110101
0.665740430355072 0.101010100110110111110111
0.8638420104980469 0.110111010010010011
0.3918175995349884 0.0110010001001110001010001
0.6584303379058838 0.1010100010001110111001
randomFloat32(4)
3.8685505390167236 11.1101111001011001010101
1.3849899768829346 1.0110001010001110101101
3.5557355880737305 11.10001110010001001011
1.9126533269882202 1.11101001101000111010011
2.8120803833007812 10.11001111111001001
randomFloat32(5,7)
6.76179838180542 110.110000110000010100111
5.768731594085693 101.110001001100101110011
5.725522041320801 101.10111001101110111101
6.2515740394592285 110.010000000110011100101
5.0234503746032715 101.000001100000000011011
randomFloat64()
0.690803412413217 0.1011000011011000011111100001000001000111101010111111
0.11257452328114703 0.0001110011010001101011110001011111011010111101100001
0.7540652142135055 0.11000001000010100110101011111010000110010010011001001
0.1101138829540963 0.00011100001100000110110001100110000111111001100000101
0.9723450582551325 0.111110001110101110011011000100011010001000001100111
randomFloat64(4)
1.4401003736030833 1.011100001010101001101011000001111001010100100110111
3.822690506829564 11.11010010100110111101100001010101100100000000100101
2.8196269628488606 10.11010001110100110001001010011000010110110000110011
1.8257031653043914 1.1101001101100001010010000101101100101111101000001
0.04597539088946645 0.000010111100010100001011000100000100101010000011111
randomFloat64(5,7)
5.916290461635426 101.11101010100100100000001011111110010111000110001111
5.595896881361192 101.10011000100011001011001010110001001111000001011
5.998995254544729 101.1111111110111110001001110010101100100000111110011
6.927475819224875 110.11101101011011110000111000100111011001101101001001
6.469594235393646 110.01111000001101110101001111101011011001111110010011
randomInteger(-0xFFFF_FFFF, 0xFFFF_FFFF)
-929633365
1560369360
-1435113722
-2519637442
-1282205992
randomInteger(0, 4)
0
4
1
2
2
randomInteger(0, Number.MAX_SAFE_INTEGER)
001F_FFFF_FFFF_FFFF == 53 bits all set (Number.MAX_SAFE_INTEGER)
000C_D943_882C_47C5
000E_E298_5576_D500
0004_7F7A_09A6_5F8B
0004_31EA_E617_4A81
0008_9221_89A0_FE6E
randomInteger(0, FF_FFFF_FFFF)
0000_00A0_4ED6_D5DE
0000_009C_7602_F5D1
0000_00CE_2800_08B7
0000_0034_C35B_D273
0000_006F_972C_022A
randomInteger(FFFF_FFFF_0000, FFFF_FFFF_FFFF)
0000_FFFF_FFFF_F919
0000_FFFF_FFFF_1F12
0000_FFFF_FFFF_46E9
0000_FFFF_FFFF_E02C
0000_FFFF_FFFF_EBEC
randomBytes(100)
Uint8Array(100) [
84, 51, 40, 249, 106, 90, 31, 200, 190, 78, 49, 41,
25, 27, 199, 199, 86, 251, 44, 162, 103, 57, 0, 193,
81, 149, 94, 36, 15, 89, 40, 240, 219, 12, 32, 223,
113, 130, 90, 113, 188, 164, 254, 76, 164, 24, 73, 146,
195, 189, 24, 56, 43, 141, 196, 127, 150, 245, 101, 204,
121, 176, 163, 171, 92, 235, 162, 37, 140, 50, 26, 243,
203, 29, 38, 199, 201, 229, 22, 234, 70, 40, 90, 18,
48, 182, 166, 5, 114, 94, 30, 146, 181, 227, 79, 209,
9, 218, 216, 18
]
RandomGenerator
1/** 2 * A `RandomGenerator` using the Sfc32 algorithm. It's compatible with any `SeedInitializer` returning unsigned 32-bit integers, e.g. `SeedInitializer_Uint32`. 3 */ 4export class RandomGenerator_Sfc32 { 5 #a; #b; #c; #counter // where the state is kept 6 static seedsNeeded = 3 // tell the SeedInitializer to call the constructor with 3 seeds (instead of the default 1) 7 constructor(uint32_a, uint32_b, uint32_c) { 8 if (arguments.length != 3) throw Error('Sfc32 require 3 integer seeds.') 9 if (typeof uint32_a != 'number' || !Number.isInteger(uint32_a)) throw Error('Sfc32 require integer seeds, this is not an integer: '+uint32_a) 10 this.#a = uint32_a >>> 0 11 this.#b = uint32_b >>> 0 12 this.#c = uint32_c >>> 0 13 this.#counter = 1 14 this.randomUint32(); this.randomUint32() // forward to a good state 15 } 16 randomUint32() { // PluggablePRNG will implement the other variants 17 let result = (this.#a + this.#b + this.#counter++) >>> 0 18 this.#a = (this.#b ^ (this.#b >>> 9)) >>> 0 19 this.#b = (this.#c + (this.#c << 3)) >>> 0 20 this.#c = (result + ((this.#c << 21) | (this.#c >>> 11))) >>> 0 21 return result 22 } 23 exportState() { 24 return [this.#a, this.#b, this.#c, this.#counter] 25 } 26 importState(state) { 27 [this.#a, this.#b, this.#c, this.#counter] = state 28 } 29}
SeedInitializer
1/** 2 * A `SeedInitializer` compatible with any `RandomGenerator` requiring unsigned 64-bit `BigInt` as seeds, `seed` can be called several times to generate more seeds from its input seed. 3 */ 4export class SeedInitializer_Uint64 { 5 constructor(seed) { 6 if (seed == undefined) seed = +new Date // "random seed" 7 let nextState = 123456n, pcg 8 for (let char of seed.toString()) { 9 pcg = new RandomGenerator_Pcg64(nextState, BigInt(char.codePointAt(0))) 10 nextState = pcg.randomUint64() 11 } 12 pcg = new RandomGenerator_Pcg64(nextState, 0n) 13 this.seed = pcg.randomUint64.bind(pcg) 14 } 15}
number
number
number
Uint8Array
number
*
Plug in the seed
, RandomGenerator
and SeedInitializer
you want to use in this PRNG instance. Has methods for getting any random number you could want.
Kind: static class of pluggable-prng
number
number
number
Uint8Array
number
*
Param | Type | Description |
---|---|---|
options | Object | An object with the options to use. |
[options.seed] | * | The seed to initialize the RandomGenerator with. If used together with a SeedInitializer it can usually be any string or number which the SeedInitializer will convert into the proper format required by the RandomGenerator (if the RandomGenerator is designed to be compatible with it). |
options.RandomGenerator | * | A class implementing the PRNG algorithm to use. |
[options.SeedInitializer] | * | If the RandomGenerator needs the seed to go through a special algorithm to convert it into the required format then supply a "seed initializer" class here. |
If this is different from undefined
then the PRNG has an async initialization and you would need to await this Promise
before you can use the PRNG.
Kind: instance property of PluggablePRNG
Check if the PRNG is async, meaning calls to it will return promises which you can resolve with await
. This must be checked after readyPromise has been awaited (if readyPromise is not undefined).
E.g. await prng.randomFloat32()
.
Kind: instance property of PluggablePRNG
number
Get a random integer from min to max. Internally it's using 1 call to randomUint32
if the difference between min
and max
is less than 4_294_967_296 (0xFFFF_FFFF), else 2 calls. If no arguments are supplied then it will pick an integer from 0x00 to 0xFFFF_FFFF.
Kind: instance method of PluggablePRNG
Returns: number
- An integer.
Param | Type | Description |
---|---|---|
[minOrMax] | number | The minimum value. |
[max] | number | The maximum value. |
number
Get a random float from 0 to 1 with 32-bit (single) precision. Optionally change this range by providing max
or min, max
. Internally it's using 1 call to randomUint32
if not given any parameters, else 2 calls.
Kind: instance method of PluggablePRNG
Returns: number
- A 32-bit float.
Param | Type | Description |
---|---|---|
[minOrMax] | number | The minimum value OR the maximum value if used alone. |
[max] | number | The maximum value. |
number
Get a random float from 0 to 1 with 64-bit (double) precision. Optionally change this range by providing max
or min, max
. Internally it's using 2 calls to randomUint32
.
Kind: instance method of PluggablePRNG
Returns: number
- A 64-bit float.
Param | Type | Description |
---|---|---|
[minOrMax] | number | The minimum value OR the maximum value if used alone. |
[max] | number | The maximum value. |
Uint8Array
Request a certain number of random bytes.
Kind: instance method of PluggablePRNG
Returns: Uint8Array
- A Uint8Array with the bytes.
Param | Type | Description |
---|---|---|
numBytes | number | The amount of bytes wanted. |
number
Get an unsigned 32-bit integer directly from the RandomGenerator
. This is the source of random bits used by all the other functions.
Kind: instance method of PluggablePRNG
Returns: number
- A 32-bit unsigned integer.
Skip the RandomGenerator
ahead this number of calls to randomUint32
, this can be used to keep two PRNGs in sync.
Kind: instance method of PluggablePRNG
Param | Type |
---|---|
numCalls | number |
*
Export the current state of the RandomGenerator
. You can then later rewind back to this state by importing it with importState
, or send it to another PluggablePRNG instance using the same RandomGenerator
to synchronize two instances.
Kind: instance method of PluggablePRNG
Returns: *
- A value representing the current state of the PRNG.
Import a known state into the RandomGenerator
to resume from that state.
Kind: instance method of PluggablePRNG
Param | Type | Description |
---|---|---|
state | * | A value representing a state of the PRNG. |
Reset the PRNG to its initial state. It "rewinds" itself back to the start so that it can be used to generate the same numbers again.
Kind: instance method of PluggablePRNG
This function allows you to change the seed without having to create a new PluggablePRNG
instance. Returns a promise if the readyPromise
property is different from undefined
(which would need to be resolved before the seed change is complete).
Kind: instance method of PluggablePRNG
Param | Type | Description |
---|---|---|
seed | * | A seed compatible with the SeedInitializer (if used) or else the RandomGenerator directly. |
Your consciousness is not a creation of your brain, it's the opposite.
Remember who you are, you have every answer inside of you.
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
0 existing vulnerabilities detected
Reason
license file detected
Details
Reason
Found 1/9 approved changesets -- score normalized to 1
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Score
Last Scanned on 2025-07-14
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More