question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Use crypto.getRandomValues for new seeds

See original GitHub issue

It’s ill advised to use plain math.random due to the low entropy available in testing environments. Instead, use getRandomValues where available (IE11+ var crypto = window.crypto || window.msCrypto;).

Update: The concern I’m trying to address here is collisions that are the result of low-entropy testing environments, not deficits to the underlying PRNG. It’s an edge case, but the fix is trivial.

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Comments:12 (6 by maintainers)

github_iconTop GitHub Comments

3reactions
victorquinncommented, Feb 10, 2016

This has come up multiple times and my answer is always the same.

First, Chance doesn’t use Math.random() under the hood to generate its random, by default it uses a Mersenne Twister. More info in the docs

It does use Math.random() by default to pick a seed for the twister if none is provided as the default. This is an important distinction.

This was intentional to provide the ability for “repeatable random” if desired by providing the same seed. This is useful for certain use cases (like unit tests where you may want repeatable results).

Second, the rationale for not using any specific crypto library under the hood was that Chance was built to work almost anywhere. It will currently run in practically any Browser or Node.js, in Mongo, in Rhino. I’ve even had people email me about successfully cross-compiling Chance to Java and other languages.

I’ve ensured this is the case by having zero dependencies, using only vanilla JS (es5), and by not depending on any specific crypto implementations (e.g. window.crypto or Node’s crypto)

If Chance instead used what you suggest (window.crypto) that limits functionality only to the browser (breaking all server-side implementations along with cross compilation), and further only to browsers that support crypto (which is admittedly becoming more prevalent but still not yet universal).

However, I anticipated this from Chance’s humble start a few years back, so back in 2013 I wrote into Chance the ability to specify an arbitrary random function of your choosing so a developer could override the default and use any method for the random number generator underlying Chance. This provides optimal flexibility.

You can simply specify the function you’d like to use as a random number generator (any function which returns a number from 0 to 1) and Chance will use your method instead of its Mersenne Twister. See the docs here.

So if you’d like to specify window.crypto for your particular application rather than the Mersenne Twister, the following snippet will do it for you:

var chance = new Chance(function() {
    var arr = new Uint32Array(1);
    window.crypto.getRandomValues(arr);
    // This jazz is necessary to translate from a random integer to a floating point from 0 to 1
    return arr[0]/(0xffffffff + 1);
});
// Now chance will use window.crypto for random rather than the Mersenne Twister

This will get you the results you’d like without limiting compatibility and without dropping the feature of being able to provide a seed and get repeatable random.

Given that not using window.crypto is a feature, not a bug, I am closing this issue.

0reactions
indoleringcommented, Feb 26, 2016

However, that turned out to be a blessing in disguise because in failing to get true random, I stumbled upon another 2 features: User supplied source of random Repeatable random, which has been a feature many (including myself) have relied upon since.

Both are killer features, I have both in my homegrown solution, but these are orthogonal issues.

And it doesn’t accomplish all that much.

Low entropy testing environments are honestly one of the few places in which seeds with low entropy can be found. Sure, tests with side-effects are somewhat rare and users can work around the issue, but it would (as you pointed out three years ago) be nice if Chance handled this on its own.

However, along with that comes the responsibility to no longer introduce potentially breaking changes for no great reason. In my opinion, adding the kind of messy script proposed above just to generate a more random seed is not terribly helpful and has the potential to introduce a lot of breakage.

I wrote the above code without much thought, here’s a better proposal that uses an enhanced version of underscore’s Node detection and produces a random integer all wrapped neatly in a try/catch.

var seed = fallbackSeed();

try {
  if(typeof window !== 'undefined' && typeof window.crypto !== 'undefined' && typeof window.crypto.getRandomValues === 'function'){ //browser
    var arr = new Uint32Array(1);
    window.crypto.getRandomValues(arr);
    seed = arr[0];
  } else if (typeof exports !== 'undefined' && this.exports !== exports){ //node
    crypto = require('crypto');
    var buf = crypto.randomBytes(4);
    var hex = buf.toString('hex');
    seed = parseInt(hex, 16);
  }
} catch(error) {
  seed = fallbackSeed();
}

//overkill
if(typeof seed !== 'number'){
  seed = fallbackSeed();
}

function fallbackSeed(){
  return Math.floor(Math.random()*Math.pow(10,13));
}

Unless someone has deliberately sabotaged the environment in a very specific way, you will get a random seed.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Crypto.getRandomValues()
getRandomValues () method lets you get cryptographically strong random values. The array given as the parameter is filled with random numbers ( ...
Read more >
Crypto.getRandomValues() - Web APIs | MDN
getRandomValues () method lets you get cryptographically strong random values. The array given as the parameter is filled with random numbers ( ...
Read more >
Crypto.getRandomValues() - Web APIs
getRandomValues () method lets you get cryptographically strong random values. ... Implementations are required to use a seed with enough entropy, ...
Read more >
Shuffling a poker deck in JavaScript with window.crypto ...
Using window.crypto.getRandomValues we can generate the required 226 bits of entropy to be used as our seed. If that still isn't enough, we...
Read more >
How to use getRandomValues function in Crypto - Tabnine
export function uuid() { return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, function(c) { return (c ^ window.crypto.getRandomValues(new ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found