5 unstable releases
Uses new Rust 2024
| 0.3.2 | Jul 10, 2025 |
|---|---|
| 0.3.1 | Jul 10, 2025 |
| 0.3.0 | Jul 10, 2025 |
| 0.2.0 | Jul 9, 2025 |
| 0.1.0 | Jul 8, 2025 |
#1030 in Command line utilities
113 downloads per month
62KB
1.5K
SLoC
jsrp
A JavaScript Randomness Predictor
Predict JS Math.random output in Node, Chrome, Firefox, and Safari with Rust!
You can use this package programmatically, or via CLI.
Important
- You must use the matching predictor for the environment! Meaning, if random numbers were generatedin Firefox, you must use the Firefox predictor, etc..
- You must generate the initial sequence, as well as expected results, from within the same context. Please see here for a more detailed explanation
- We recommend you provide at least 4 random numbers in the initial sequence
- Please see here for a list of known issues!
Installation
To use programmatically
cargo add jsrp
To use CLI
This installs jsrp globally! You will be able to use the jsrp command system wide.
cargo install jsrp
Usage
Firefox
See here for known Firefox issues
use jsrp::FirefoxPredictor;
let mut ffp = FirefoxPredictor::new(vec![/*
4 random numbers copied from
using Math.random in Firefox.
*/]);
let next = ffp.predict_next()?;
// Run another Math.random() in
// Firefox to validate `next`.
Chrome
use jsrp::ChromePredictor;
let mut chrp = ChromePredictor::new(vec![/*
4 random numbers copied from
using Math.random in Chrome.
*/]);
let next = chrp.predict_next()?;
// Run another Math.random() in
// Chrome to validate `next`.
Node
See here for known Node issues
- You must provide a
Node.jsversion (just themajorversion) when callingnew!
# You can get your current `Node.js` version
# by running the following command in your
# terminal:
node -p "process.versions.node.split('.')[0]"
#-> 24
Once you have your Node.js major version: (which we are using 24 as an example):
use jsrp::{NodePredictor, NodeJsMajorVersion};
let mut np_v24 = NodePredictor::new(
NodeJsMajorVersion::V24,
vec![/*
4 random numbers copied from
using Math.random in the specific
Node.js version you provided.
*/],
);
let next = np_v24.predict_next()?;
// Run another Math.random() in
// Node.js to validate `next`.
Make Predictions for Different Node.js Versions
If you have a sequence of random numbers that someone generated in Node.js v22.x.x (or whatever version) you can still run the predictor against them, regardless of your current Node.js version.
Just specify "that" version:
use jsrp::NodePredictor;
let mut np_vX = NodePredictor::new(
that_nodejs_major_version,
vec![/*
4 random numbers copied from
using Math.random in the specific
Node.js version you provided.
*/],
);
let next = np_vX.predict_next()?;
// Run another Math.random() in
// Node.js to validate `next`.
Safari
use jsrp::SafariPredictor;
let mut sp = SafariPredictor::new(vec![/*
4 random numbers copied from
using Math.random in Safari.
*/]);
let next = sp.predict_next()?;
// Run another Math.random() in
// Safari to validate `next`.
CLI
- Use
jsrp --helpto get a full list of commands/arguments (as well as their shorthand equivalent). - Use
jsrp <environment> --helpto get a full list of commands/arguments for a specific environment. - Each number within
--sequenceshould be separated by a space. - By default we provide 10 predictions (if
--predictionswas not provided). - You can export results to JSON (more info below).
- You can provide expected results so that we can automatically validate our predictions (more info below).
# Node - make 12 predictions
# Must provide a Node.js major version!
# Major versions must start with a "v"
jsrp node --sequence 0.1 0.2 0.3 --major-version v24 --predictions 12
jsrp node --sequence 0.1 0.2 0.3 --major-version v24
# Shorthand
jsrp node -s 0.1 0.2 0.3 -m v24 -p 12
# Firefox
jsrp firefox -s ... -p N
# Chrome
jsrp chrome -s ... -p N
# Safari
jsrp safari -s ... -p N
Validate Expected Results
If you already have the expected sequence, you can provide it via the --expected, or -x, flag. If provided, we will automatically validate our predictions.
# This actually works! Try it in the CLI
jsrp node\
--major-version v24\
--sequence 0.15825075235897956\
0.6837830031246955\
0.2352848927050296\
0.6995244175841968\
--expected 0.32903013894382993
# {
# "environment": "Node.js v24",
# "expected": [
# 0.32903013894382993
# ],
# "is_accurate": true,
# "predictions": [
# 0.32903013894382993
# ],
# "sequence": [
# 0.15825075235897956,
# 0.6837830031246955,
# 0.2352848927050296,
# 0.6995244175841968
# ]
# }
Export Results to JSON
# You can add `--export` (`-e` for short) to any command,
# which will export the results to .json.
# The file path MUST end in .json!!!
jsrp <environment> -s ... -e ./some/path/results.json
Known Issues
Generation Context
- You can't generate the initial sequence from the console in "browser tab A", and then generate the expected results from the console in a different browser tab. Both the sequence and expected numbers should have been generated in "browser tab A"
- If you do
node -p "Array.from({ length: 4 }, Math.random)"to generate the initial sequence, you will have no way of verifying our predictions. Instead, you would need to enter the Node REPL (because all generated random numbers would be from the same context)- eg enter
$ nodefrom terminal, and then once in REPL> Array.from({ length: 4 }, Math.random)for initial sequence and> Array.from({ length: 10 }, Math.random)for expected results.
- eg enter
Node
Random Number Pool Exhaustion
TLDR; If number of predictions + sequence length > 64, we cannot make accurate predictions. We call this "pool exhaustion".
Why does this happen?
- Node generate 64 "random" numbers at a time, which they cache in a "pool"
- Source code that shows how they build the cache
- Source code showing cache size
- A seed is used to generate these "random" numbers
- Solving for that seed is what allows us to predict future
Math.randomoutput - When you call
Math.random()they grab a number from this "pool" and return it to you- Source code that shows how they pull from cache and return a random number to you, specifically here
- When that "pool" is exhausted, they generate a new "pool", with a new/different seed
- Source code that shows how they refill the cache, specifically here
- This means we cannot make accurate predictions for the new pool using the old pools seed
How we handle it
- When using the CLI, if
number of predictions+sequence length>64, we will show a warning as well as truncate "number of predictions" to be within the allowed bounds. - For example, if you provided
[1, 2, 3, 4]as the sequence, which has a length of 4, the max amount of predictions we can successfully make is 60 (because 64 - 4 = 60) - If the "length of the sequence" on it's own is >= 64, we will throw an error because we have no room for predictions, the entire pool was exhausted on the sequence
Firefox
Random Number Generation in Console
You must disable "Instant Evaluation", otherwise your predictions may show incorrectly. Especially if you use more than one call to generate the initial sequence + expected values.
How to disable
If you do not want to disable "Instant Evaluation"
- You'll need to generate initial sequence + expected values in one command.
- So instead of using two (or more) calls to
Math.random:
/** Pretend this is the console */
// Output used as initial sequence.
Array.from({ length: 4 }, Math.random);
// Output used for validating predictions.
Array.from({ length: 10 }, Math.random);
- You'll need to do:
/** Pretend this is the console */
// Only use one call! Manually separate numbers!
Array.from({ length: 6 }, Math.random);
[
// --------------------|
0.5654163987207667, // |
0.7409356182179403, // | --> Use "these" numbers as initial sequence
0.46136469064448193, //|
0.18124646315195891, //|
// --------------------|
0.25678544986069995, // --> Use the rest of the numbers for validation
0.5543550504255771,
];
Safari
NONE
Chrome
NONE
Dependencies
~2.1–5MB
~94K SLoC