diff --git a/src/blog/math-random.md b/src/blog/math-random.md index 2cd1cafe..6b5144cb 100644 --- a/src/blog/math-random.md +++ b/src/blog/math-random.md @@ -13,11 +13,11 @@ description: 'V8’s Math.random implementation now uses an algorithm called xor — _[ES 2015, section 20.2.2.27](http://tc39.es/ecma262/#sec-math.random)_ -`Math.random()` is the most well-known and frequently-used source of randomness in Javascript. In V8 and most other Javascript engines, it is implemented using a [pseudo-random number generator](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) (PRNG). As with all PRNGs, the random number is derived from an internal state, which is altered by a fixed algorithm for every new random number. So for a given initial state, the sequence of random numbers is deterministic. Since the bit size n of the internal state is limited, the numbers that a PRNG generates will eventually repeat themselves. The upper bound for the period length of this [permutation cycle](https://en.wikipedia.org/wiki/Cyclic_permutation) is 2n. +`Math.random()` is the most well-known and frequently-used source of randomness in JavaScript. In V8 and most other JavaScript engines, it is implemented using a [pseudo-random number generator](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) (PRNG). As with all PRNGs, the random number is derived from an internal state, which is altered by a fixed algorithm for every new random number. So for a given initial state, the sequence of random numbers is deterministic. Since the bit size n of the internal state is limited, the numbers that a PRNG generates will eventually repeat themselves. The upper bound for the period length of this [permutation cycle](https://en.wikipedia.org/wiki/Cyclic_permutation) is 2n. There are many different PRNG algorithms; among the most well-known ones are [Mersenne-Twister](https://en.wikipedia.org/wiki/Mersenne_Twister) and [LCG](https://en.wikipedia.org/wiki/Linear_congruential_generator). Each has its particular characteristics, advantages, and drawbacks. Ideally, it would use as little memory as possible for the initial state, be quick to perform, have a large period length, and offer a high quality random distribution. While memory usage, performance, and period length can easily be measured or calculated, the quality is harder to determine. There is a lot of math behind statistical tests to check the quality of random numbers. The de-facto standard PRNG test suite, [TestU01](http://simul.iro.umontreal.ca/testu01/tu01.html), implements many of these tests. -Until [recently](https://github.com/v8/v8/blob/ceade6cf239e0773213d53d55c36b19231c820b5/src/js/math.js#L143) (up to version 4.9.40), V8’s choice of PRNG was MWC1616 (multiply with carry, combining two 16-bit parts). It uses 64 bits of internal state and looks roughly like this: +Until [late 2015](https://github.com/v8/v8/blob/ceade6cf239e0773213d53d55c36b19231c820b5/src/js/math.js#L143) (up to version 4.9.40), V8’s choice of PRNG was MWC1616 (multiply with carry, combining two 16-bit parts). It uses 64 bits of internal state and looks roughly like this: ```cpp uint32_t state0 = 1; @@ -39,10 +39,10 @@ MWC1616 uses little memory and is pretty fast to compute, but unfortunately offe This has been [pointed out](https://medium.com/@betable/tifu-by-using-math-random-f1c308c4fd9d) to us, and having understood the problem and after some research, we decided to reimplement `Math.random` based on an algorithm called [xorshift128+](http://vigna.di.unimi.it/ftp/papers/xorshiftplus.pdf). It uses 128 bits of internal state, has a period length of 2128 - 1, and passes all tests from the TestU01 suite. -The implementation [landed in V8 v4.9.41.0](https://github.com/v8/v8/blob/085fed0fb5c3b0136827b5d7c190b4bd1c23a23e/src/base/utils/random-number-generator.h#L102) within a few days of us becoming aware of the issue. It will become available with Chrome 49. Both [Firefox](https://bugzilla.mozilla.org/show_bug.cgi?id=322529#c99) and [Safari](https://bugs.webkit.org/show_bug.cgi?id=151641) switched to xorshift128+ as well. +The implementation [landed in V8 v4.9.41.0](https://github.com/v8/v8/blob/085fed0fb5c3b0136827b5d7c190b4bd1c23a23e/src/base/utils/random-number-generator.h#L102) within a few days of us becoming aware of the issue. It became available with Chrome 49. Both [Firefox](https://bugzilla.mozilla.org/show_bug.cgi?id=322529#c99) and [Safari](https://bugs.webkit.org/show_bug.cgi?id=151641) switched to xorshift128+ as well. -In V8 7.1 the implemementation was adjusted again [CL](https://chromium-review.googlesource.com/c/v8/v8/+/1238551/5) relaying only on state0. Please find further implementation details in the [source code](https://source.chromium.org/chromium/chromium/src/+/main:v8/src/base/utils/random-number-generator.h;l=119?q=XorShift128&sq=&ss=chromium). +In V8 v7.1 the implementation was adjusted again [CL](https://chromium-review.googlesource.com/c/v8/v8/+/1238551/5) relying only on state0. Please find further implementation details in the [source code](https://source.chromium.org/chromium/chromium/src/+/main:v8/src/base/utils/random-number-generator.h;l=119?q=XorShift128&sq=&ss=chromium). -Make no mistake however: even though xorshift128+ is a huge improvement over MWC1616, it still is not [cryptographically secure](https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator). For use cases such as hashing, signature generation, and encryption/decryption, ordinary PRNGs are unsuitable. The Web Cryptography API introduces [`window.crypto.getRandomValues`](https://developer.mozilla.org/en-US/docs/Web/API/RandomSource/getRandomValues), a method that returns cryptographically secure random values, at a performance cost. +Make no mistake however: even though xorshift128+ is a huge improvement over MWC1616, it is still not [cryptographically secure](https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator). For use cases such as hashing, signature generation, and encryption/decryption, ordinary PRNGs are unsuitable. The Web Cryptography API introduces [`window.crypto.getRandomValues`](https://developer.mozilla.org/en-US/docs/Web/API/RandomSource/getRandomValues), a method that returns cryptographically secure random values, at a performance cost. Please keep in mind, if you find areas of improvement in V8 and Chrome, even ones that — like this one — do not directly affect spec compliance, stability, or security, please file [an issue on our bug tracker](https://bugs.chromium.org/p/v8/issues/entry?template=Defect%20report%20from%20user).