237 lines
6.8 KiB
JavaScript
237 lines
6.8 KiB
JavaScript
(function (global, pool, math, width, chunks, digits, module, define, rngname) {
|
|
//
|
|
// The following constants are related to IEEE 754 limits.
|
|
//
|
|
var startdenom = math.pow(width, chunks),
|
|
significance = math.pow(2, digits),
|
|
overflow = significance * 2,
|
|
mask = width - 1,
|
|
nodecrypto;
|
|
|
|
//
|
|
// seedrandom()
|
|
// This is the seedrandom function described above.
|
|
//
|
|
var impl = (math["seed" + rngname] = function (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);
|
|
|
|
// 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 ||
|
|
// If called as a method of Math (Math.seedrandom()), mutate Math.random
|
|
// because that is how seedrandom.js has worked since v1.0. Otherwise,
|
|
// it is a newer calling convention, so return the prng directly.
|
|
function (prng, seed, is_math_call) {
|
|
if (is_math_call) {
|
|
math[rngname] = prng;
|
|
return seed;
|
|
} else return prng;
|
|
}
|
|
)(
|
|
// This function returns a random double in [0, 1) that contains
|
|
// randomness in every bit of the mantissa of the IEEE 754 value.
|
|
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).
|
|
},
|
|
shortseed,
|
|
"global" in options ? options.global : this == math
|
|
);
|
|
});
|
|
|
|
//
|
|
// 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).
|
|
//
|
|
/** @constructor */
|
|
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);
|
|
}
|
|
|
|
//
|
|
// 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 if available.
|
|
//
|
|
/** @param {Uint8Array|Navigator=} seed */
|
|
function autoseed(seed) {
|
|
try {
|
|
if (nodecrypto) return tostring(nodecrypto.randomBytes(width));
|
|
global.crypto.getRandomValues((seed = new Uint8Array(width)));
|
|
return tostring(seed);
|
|
} catch (e) {
|
|
return [
|
|
+new Date(),
|
|
global,
|
|
(seed = global.navigator) && seed.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[rngname](), pool);
|
|
|
|
//
|
|
// Nodejs and AMD support: export the implementation as a module using
|
|
// either convention.
|
|
//
|
|
if (module && module.exports) {
|
|
module.exports = impl;
|
|
try {
|
|
// When in node.js, try using crypto package for autoseeding.
|
|
nodecrypto = require("crypto");
|
|
} catch (ex) {}
|
|
} else if (define && define.amd) {
|
|
define(function () {
|
|
return impl;
|
|
});
|
|
}
|
|
|
|
//
|
|
// Node.js native crypto support.
|
|
//
|
|
|
|
// End anonymous scope, and pass initial values.
|
|
})(
|
|
this, // global window object
|
|
[], // pool: entropy pool starts empty
|
|
Math, // math: package containing random, pow, and seedrandom
|
|
256, // width: each RC4 output is 0 <= x < 256
|
|
6, // chunks: at least six RC4 outputs for each double
|
|
52, // digits: there are 52 significant digits in a double
|
|
typeof module == "object" && module, // present in node.js
|
|
typeof define == "function" && define, // present with an AMD loader
|
|
"random" // rngname: name for Math.random and Math.seedrandom
|
|
);
|
|
|