| /* |
| Copyright 2019 David Bau. |
| |
| Permission is hereby granted, free of charge, to any person obtaining |
| a copy of this software and associated documentation files (the |
| "Software"), to deal in the Software without restriction, including |
| without limitation the rights to use, copy, modify, merge, publish, |
| distribute, sublicense, and/or sell copies of the Software, and to |
| permit persons to whom the Software is furnished to do so, subject to |
| the following conditions: |
| |
| The above copyright notice and this permission notice shall be |
| included in all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
| CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| |
| */ |
| |
| (function (global, pool, math) { |
| // |
| // The following constants are related to IEEE 754 limits. |
| // |
| |
| var width = 256, // each RC4 output is 0 <= x < 256 |
| chunks = 6, // at least six RC4 outputs for each double |
| digits = 52, // there are 52 significant digits in a double |
| rngname = 'random', // rngname: name for Math.random and Math.seedrandom |
| startdenom = math.pow(width, chunks), |
| significance = math.pow(2, digits), |
| overflow = significance * 2, |
| mask = width - 1, |
| nodecrypto; // node.js crypto module, initialized at the bottom. |
| |
| // |
| // seedrandom() |
| // This is the seedrandom function described above. |
| // |
| function seedrandom(seed, options, callback) { |
| var key = []; |
| options = options == true ? { entropy: true } : options || {}; |
| |
| // Flatten the seed string or build one from local entropy if needed. |
| var shortseed = mixkey( |
| flatten( |
| options.entropy |
| ? [seed, tostring(pool)] |
| : seed == null |
| ? autoseed() |
| : seed, |
| 3 |
| ), |
| key |
| ); |
| |
| // Use the seed to initialize an ARC4 generator. |
| var arc4 = new ARC4(key); |
| |
| // This function returns a random double in [0, 1) that contains |
| // randomness in every bit of the mantissa of the IEEE 754 value. |
| var prng = function () { |
| var n = arc4.g(chunks), // Start with a numerator n < 2 ^ 48 |
| d = startdenom, // and denominator d = 2 ^ 48. |
| x = 0; // and no 'extra last byte'. |
| while (n < significance) { |
| // Fill up all significant digits by |
| n = (n + x) * width; // shifting numerator and |
| d *= width; // denominator and generating a |
| x = arc4.g(1); // new least-significant-byte. |
| } |
| while (n >= overflow) { |
| // To avoid rounding up, before adding |
| n /= 2; // last byte, shift everything |
| d /= 2; // right using integer math until |
| x >>>= 1; // we have exactly the desired bits. |
| } |
| return (n + x) / d; // Form the number within [0, 1). |
| }; |
| |
| prng.int32 = function () { |
| return arc4.g(4) | 0; |
| }; |
| prng.quick = function () { |
| return arc4.g(4) / 0x100000000; |
| }; |
| prng.double = prng; |
| |
| // Mix the randomness into accumulated entropy. |
| mixkey(tostring(arc4.S), pool); |
| |
| // Calling convention: what to return as a function of prng, seed, is_math. |
| return ( |
| options.pass || |
| callback || |
| function (prng, seed, is_math_call, state) { |
| if (state) { |
| // Load the arc4 state from the given state if it has an S array. |
| if (state.S) { |
| copy(state, arc4); |
| } |
| // Only provide the .state method if requested via options.state. |
| prng.state = function () { |
| return copy(arc4, {}); |
| }; |
| } |
| |
| // If called as a method of Math (Math.seedrandom()), mutate |
| // Math.random because that is how seedrandom.js has worked since v1.0. |
| if (is_math_call) { |
| math[rngname] = prng; |
| return seed; |
| } |
| |
| // Otherwise, it is a newer calling convention, so return the |
| // prng directly. |
| else return prng; |
| } |
| )( |
| prng, |
| shortseed, |
| 'global' in options ? options.global : this == math, |
| options.state |
| ); |
| } |
| |
| // |
| // ARC4 |
| // |
| // An ARC4 implementation. The constructor takes a key in the form of |
| // an array of at most (width) integers that should be 0 <= x < (width). |
| // |
| // The g(count) method returns a pseudorandom integer that concatenates |
| // the next (count) outputs from ARC4. Its return value is a number x |
| // that is in the range 0 <= x < (width ^ count). |
| // |
| function ARC4(key) { |
| var t, |
| keylen = key.length, |
| me = this, |
| i = 0, |
| j = (me.i = me.j = 0), |
| s = (me.S = []); |
| |
| // The empty key [] is treated as [0]. |
| if (!keylen) { |
| key = [keylen++]; |
| } |
| |
| // Set up S using the standard key scheduling algorithm. |
| while (i < width) { |
| s[i] = i++; |
| } |
| for (i = 0; i < width; i++) { |
| s[i] = s[(j = mask & (j + key[i % keylen] + (t = s[i])))]; |
| s[j] = t; |
| } |
| |
| // The "g" method returns the next (count) outputs as one number. |
| (me.g = function (count) { |
| // Using instance members instead of closure state nearly doubles speed. |
| var t, |
| r = 0, |
| i = me.i, |
| j = me.j, |
| s = me.S; |
| while (count--) { |
| t = s[(i = mask & (i + 1))]; |
| r = |
| r * width + s[mask & ((s[i] = s[(j = mask & (j + t))]) + (s[j] = t))]; |
| } |
| me.i = i; |
| me.j = j; |
| return r; |
| // For robust unpredictability, the function call below automatically |
| // discards an initial batch of values. This is called RC4-drop[256]. |
| // See http://google.com/search?q=rsa+fluhrer+response&btnI |
| })(width); |
| } |
| |
| // |
| // copy() |
| // Copies internal state of ARC4 to or from a plain object. |
| // |
| function copy(f, t) { |
| t.i = f.i; |
| t.j = f.j; |
| t.S = f.S.slice(); |
| return t; |
| } |
| |
| // |
| // flatten() |
| // Converts an object tree to nested arrays of strings. |
| // |
| function flatten(obj, depth) { |
| var result = [], |
| typ = typeof obj, |
| prop; |
| if (depth && typ == 'object') { |
| for (prop in obj) { |
| try { |
| result.push(flatten(obj[prop], depth - 1)); |
| } catch (e) {} |
| } |
| } |
| return result.length ? result : typ == 'string' ? obj : obj + '\0'; |
| } |
| |
| // |
| // mixkey() |
| // Mixes a string seed into a key that is an array of integers, and |
| // returns a shortened string seed that is equivalent to the result key. |
| // |
| function mixkey(seed, key) { |
| var stringseed = seed + '', |
| smear, |
| j = 0; |
| while (j < stringseed.length) { |
| key[mask & j] = |
| mask & ((smear ^= key[mask & j] * 19) + stringseed.charCodeAt(j++)); |
| } |
| return tostring(key); |
| } |
| |
| // |
| // autoseed() |
| // Returns an object for autoseeding, using window.crypto and Node crypto |
| // module if available. |
| // |
| function autoseed() { |
| try { |
| var out; |
| if (nodecrypto && (out = nodecrypto.randomBytes)) { |
| // The use of 'out' to remember randomBytes makes tight minified code. |
| out = out(width); |
| } else { |
| out = new Uint8Array(width); |
| (global.crypto || global.msCrypto).getRandomValues(out); |
| } |
| return tostring(out); |
| } catch (e) { |
| var browser = global.navigator, |
| plugins = browser && browser.plugins; |
| return [+new Date(), global, plugins, global.screen, tostring(pool)]; |
| } |
| } |
| |
| // |
| // tostring() |
| // Converts an array of charcodes to a string |
| // |
| function tostring(a) { |
| return String.fromCharCode.apply(0, a); |
| } |
| |
| // |
| // When seedrandom.js is loaded, we immediately mix a few bits |
| // from the built-in RNG into the entropy pool. Because we do |
| // not want to interfere with deterministic PRNG state later, |
| // seedrandom will not call math.random on its own again after |
| // initialization. |
| // |
| mixkey(math.random(), pool); |
| |
| // |
| // Nodejs and AMD support: export the implementation as a module using |
| // either convention. |
| // |
| if (typeof module == 'object' && module.exports) { |
| module.exports = seedrandom; |
| // When in node.js, try using crypto package for autoseeding. |
| try { |
| nodecrypto = require('crypto'); |
| } catch (ex) {} |
| } else if (typeof define == 'function' && define.amd) { |
| define(function () { |
| return seedrandom; |
| }); |
| } else { |
| // When included as a plain script, set up Math.seedrandom global. |
| math['seed' + rngname] = seedrandom; |
| } |
| |
| // End anonymous scope, and pass initial values. |
| })( |
| // global: `self` in browsers (including strict mode and web workers), |
| // otherwise `this` in Node and other environments |
| typeof self !== 'undefined' ? self : this, |
| [], // pool: entropy pool starts empty |
| Math // math: package containing random, pow, and seedrandom |
| ); |