js/src/parjs-benchmarks/seedrandom.js

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 // seedrandom.js version 2.1.
     2 // Author: David Bau
     3 // Date: 2013 Mar 16
     4 //
     5 // Defines a method Math.seedrandom() that, when called, substitutes
     6 // an explicitly seeded RC4-based algorithm for Math.random().  Also
     7 // supports automatic seeding from local or network sources of entropy.
     8 //
     9 // http://davidbau.com/encode/seedrandom.js
    10 // http://davidbau.com/encode/seedrandom-min.js
    11 //
    12 // Usage:
    13 //
    14 //   <script src=http://davidbau.com/encode/seedrandom-min.js></script>
    15 //
    16 //   Math.seedrandom('yay.');  Sets Math.random to a function that is
    17 //                             initialized using the given explicit seed.
    18 //
    19 //   Math.seedrandom();        Sets Math.random to a function that is
    20 //                             seeded using the current time, dom state,
    21 //                             and other accumulated local entropy.
    22 //                             The generated seed string is returned.
    23 //
    24 //   Math.seedrandom('yowza.', true);
    25 //                             Seeds using the given explicit seed mixed
    26 //                             together with accumulated entropy.
    27 //
    28 //   <script src="https://jsonlib.appspot.com/urandom?callback=Math.seedrandom">
    29 //   </script>                 Seeds using urandom bits from a server.
    30 //
    31 // More advanced examples:
    32 //
    33 //   Math.seedrandom("hello.");           // Use "hello." as the seed.
    34 //   document.write(Math.random());       // Always 0.9282578795792454
    35 //   document.write(Math.random());       // Always 0.3752569768646784
    36 //   var rng1 = Math.random;              // Remember the current prng.
    37 //
    38 //   var autoseed = Math.seedrandom();    // New prng with an automatic seed.
    39 //   document.write(Math.random());       // Pretty much unpredictable x.
    40 //
    41 //   Math.random = rng1;                  // Continue "hello." prng sequence.
    42 //   document.write(Math.random());       // Always 0.7316977468919549
    43 //
    44 //   Math.seedrandom(autoseed);           // Restart at the previous seed.
    45 //   document.write(Math.random());       // Repeat the 'unpredictable' x.
    46 //
    47 //   function reseed(event, count) {      // Define a custom entropy collector.
    48 //     var t = [];
    49 //     function w(e) {
    50 //       t.push([e.pageX, e.pageY, +new Date]);
    51 //       if (t.length < count) { return; }
    52 //       document.removeEventListener(event, w);
    53 //       Math.seedrandom(t, true);        // Mix in any previous entropy.
    54 //     }
    55 //     document.addEventListener(event, w);
    56 //   }
    57 //   reseed('mousemove', 100);            // Reseed after 100 mouse moves.
    58 //
    59 // Version notes:
    60 //
    61 // The random number sequence is the same as version 1.0 for string seeds.
    62 // Version 2.0 changed the sequence for non-string seeds.
    63 // Version 2.1 speeds seeding and uses window.crypto to autoseed if present.
    64 //
    65 // The standard ARC4 key scheduler cycles short keys, which means that
    66 // seedrandom('ab') is equivalent to seedrandom('abab') and 'ababab'.
    67 // Therefore it is a good idea to add a terminator to avoid trivial
    68 // equivalences on short string seeds, e.g., Math.seedrandom(str + '\0').
    69 // Starting with version 2.0, a terminator is added automatically for
    70 // non-string seeds, so seeding with the number 111 is the same as seeding
    71 // with '111\0'.
    72 //
    73 // When seedrandom() is called with zero args, it uses a seed
    74 // drawn from the browser crypto object if present.  If there is no
    75 // crypto support, seedrandom() uses the current time, the native rng,
    76 // and a walk of several DOM objects to collect a few bits of entropy.
    77 //
    78 // Each time the one- or two-argument forms of seedrandom are called,
    79 // entropy from the passed seed is accumulated in a pool to help generate
    80 // future seeds for the zero- and two-argument forms of seedrandom.
    81 //
    82 // On speed - This javascript implementation of Math.random() is about
    83 // 3-10x slower than the built-in Math.random() because it is not native
    84 // code, but that is typically fast enough.  Some details (timings on
    85 // Chrome 25 on a 2010 vintage macbook):
    86 //
    87 // seeded Math.random()          - avg less than 0.0002 milliseconds per call
    88 // seedrandom('explicit.')       - avg less than 0.2 milliseconds per call
    89 // seedrandom('explicit.', true) - avg less than 0.2 milliseconds per call
    90 // seedrandom() with crypto      - avg less than 0.2 milliseconds per call
    91 // seedrandom() without crypto   - avg about 12 milliseconds per call
    92 //
    93 // On a 2012 windows 7 1.5ghz i5 laptop, Chrome, Firefox 19, IE 10, and
    94 // Opera have similarly fast timings.  Slowest numbers are on Opera, with
    95 // about 0.0005 milliseconds per seeded Math.random() and 15 milliseconds
    96 // for autoseeding.
    97 //
    98 // LICENSE (BSD):
    99 //
   100 // Copyright 2013 David Bau, all rights reserved.
   101 //
   102 // Redistribution and use in source and binary forms, with or without
   103 // modification, are permitted provided that the following conditions are met:
   104 //
   105 //   1. Redistributions of source code must retain the above copyright
   106 //      notice, this list of conditions and the following disclaimer.
   107 //
   108 //   2. Redistributions in binary form must reproduce the above copyright
   109 //      notice, this list of conditions and the following disclaimer in the
   110 //      documentation and/or other materials provided with the distribution.
   111 //
   112 //   3. Neither the name of this module nor the names of its contributors may
   113 //      be used to endorse or promote products derived from this software
   114 //      without specific prior written permission.
   115 //
   116 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   117 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   118 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   119 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   120 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   121 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   122 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   123 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   124 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   125 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   126 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   127 //
   128 /**
   129  * All code is in an anonymous closure to keep the global namespace clean.
   130  */
   131 (function (
   132     global, pool, math, width, chunks, digits) {
   134 //
   135 // The following constants are related to IEEE 754 limits.
   136 //
   137 var startdenom = math.pow(width, chunks),
   138     significance = math.pow(2, digits),
   139     overflow = significance * 2,
   140     mask = width - 1;
   142 //
   143 // seedrandom()
   144 // This is the seedrandom function described above.
   145 //
   146 math['seedrandom'] = function(seed, use_entropy) {
   147   var key = [];
   149   // Flatten the seed string or build one from local entropy if needed.
   150   var shortseed = mixkey(flatten(
   151     use_entropy ? [seed, tostring(pool)] :
   152     0 in arguments ? seed : autoseed(), 3), key);
   154   // Use the seed to initialize an ARC4 generator.
   155   var arc4 = new ARC4(key);
   157   // Mix the randomness into accumulated entropy.
   158   mixkey(tostring(arc4.S), pool);
   160   // Override Math.random
   162   // This function returns a random double in [0, 1) that contains
   163   // randomness in every bit of the mantissa of the IEEE 754 value.
   165   math['random'] = function() {         // Closure to return a random double:
   166     var n = arc4.g(chunks),             // Start with a numerator n < 2 ^ 48
   167         d = startdenom,                 //   and denominator d = 2 ^ 48.
   168         x = 0;                          //   and no 'extra last byte'.
   169     while (n < significance) {          // Fill up all significant digits by
   170       n = (n + x) * width;              //   shifting numerator and
   171       d *= width;                       //   denominator and generating a
   172       x = arc4.g(1);                    //   new least-significant-byte.
   173     }
   174     while (n >= overflow) {             // To avoid rounding up, before adding
   175       n /= 2;                           //   last byte, shift everything
   176       d /= 2;                           //   right using integer math until
   177       x >>>= 1;                         //   we have exactly the desired bits.
   178     }
   179     return (n + x) / d;                 // Form the number within [0, 1).
   180   };
   182   // Return the seed that was used
   183   return shortseed;
   184 };
   186 //
   187 // ARC4
   188 //
   189 // An ARC4 implementation.  The constructor takes a key in the form of
   190 // an array of at most (width) integers that should be 0 <= x < (width).
   191 //
   192 // The g(count) method returns a pseudorandom integer that concatenates
   193 // the next (count) outputs from ARC4.  Its return value is a number x
   194 // that is in the range 0 <= x < (width ^ count).
   195 //
   196 /** @constructor */
   197 function ARC4(key) {
   198   var t, keylen = key.length,
   199       me = this, i = 0, j = me.i = me.j = 0, s = me.S = [];
   201   // The empty key [] is treated as [0].
   202   if (!keylen) { key = [keylen++]; }
   204   // Set up S using the standard key scheduling algorithm.
   205   while (i < width) {
   206     s[i] = i++;
   207   }
   208   for (i = 0; i < width; i++) {
   209     s[i] = s[j = mask & (j + key[i % keylen] + (t = s[i]))];
   210     s[j] = t;
   211   }
   213   // The "g" method returns the next (count) outputs as one number.
   214   (me.g = function(count) {
   215     // Using instance members instead of closure state nearly doubles speed.
   216     var t, r = 0,
   217         i = me.i, j = me.j, s = me.S;
   218     while (count--) {
   219       t = s[i = mask & (i + 1)];
   220       r = r * width + s[mask & ((s[i] = s[j = mask & (j + t)]) + (s[j] = t))];
   221     }
   222     me.i = i; me.j = j;
   223     return r;
   224     // For robust unpredictability discard an initial batch of values.
   225     // See http://www.rsa.com/rsalabs/node.asp?id=2009
   226   })(width);
   227 }
   229 //
   230 // flatten()
   231 // Converts an object tree to nested arrays of strings.
   232 //
   233 function flatten(obj, depth) {
   234   var result = [], typ = (typeof obj)[0], prop;
   235   if (depth && typ == 'o') {
   236     for (prop in obj) {
   237       if (obj.hasOwnProperty(prop)) {
   238         try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {}
   239       }
   240     }
   241   }
   242   return (result.length ? result : typ == 's' ? obj : obj + '\0');
   243 }
   245 //
   246 // mixkey()
   247 // Mixes a string seed into a key that is an array of integers, and
   248 // returns a shortened string seed that is equivalent to the result key.
   249 //
   250 function mixkey(seed, key) {
   251   var stringseed = seed + '', smear, j = 0;
   252   while (j < stringseed.length) {
   253     key[mask & j] =
   254       mask & ((smear ^= key[mask & j] * 19) + stringseed.charCodeAt(j++));
   255   }
   256   return tostring(key);
   257 }
   259 //
   260 // autoseed()
   261 // Returns an object for autoseeding, using window.crypto if available.
   262 //
   263 /** @param {Uint8Array=} seed */
   264 function autoseed(seed) {
   265   try {
   266     global.crypto.getRandomValues(seed = new Uint8Array(width));
   267     return tostring(seed);
   268   } catch (e) {
   269     return [+new Date, global.document, global.history,
   270             global.navigator, global.screen, tostring(pool)];
   271   }
   272 }
   274 //
   275 // tostring()
   276 // Converts an array of charcodes to a string
   277 //
   278 function tostring(a) {
   279   return String.fromCharCode.apply(0, a);
   280 }
   282 //
   283 // When seedrandom.js is loaded, we immediately mix a few bits
   284 // from the built-in RNG into the entropy pool.  Because we do
   285 // not want to intefere with determinstic PRNG state later,
   286 // seedrandom will not call math.random on its own again after
   287 // initialization.
   288 //
   289 mixkey(math.random(), pool);
   291 // End anonymous scope, and pass initial values.
   292 })(
   293   this,   // global window object
   294   [],     // pool: entropy pool starts empty
   295   Math,   // math: package containing random, pow, and seedrandom
   296   256,    // width: each RC4 output is 0 <= x < 256
   297   6,      // chunks: at least six RC4 outputs for each double
   298   52      // digits: there are 52 significant digits in a double
   299 );

mercurial