├── LICENSE ├── README.md ├── isaacCSPRNG-1.1.js └── isaacCSPRNG-1.1.min.js /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2017, William McMeans 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🔣 isaacCSPRNG [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://GitHub.com/Naereen/StrapDown.js/graphs/commit-activity) [![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) 2 | [ISAAC](https://en.wikipedia.org/wiki/ISAAC_(cipher)) is a *cryptographically secure* pseudo-random number generator ([CSPRNG](https://en.wikipedia.org/wiki/Cryptographically-secure_pseudorandom_number_generator)), meant to be usable as a [stream cipher](https://archive.is/cOe1D), created by [Robert J. Jenkins Jr.](https://en.wikipedia.org/wiki/Robert_John_Jenkins_Junior), in 1996, based on [RC4](https://en.wikipedia.org/wiki/RC4). Designed for speed and security, ISAAC (Indirection, Shift, Accumulate, Add, and Count) generates 32-bit random numbers. On average, cycles are 28295 values long, and are guaranteed to be at least 240 values long. The results are uniformly distributed, unbiased, and unpredictable unless you know the seed. Speaking of which, it’s the responsibility of the user to seed ISAAC with a strong entropy source. 3 | 4 | Internally, my implementation here is largely Rinquin’s logic (see [REFS](https://github.com/macmcmeans/isaacCSPRNG/blob/master/README.md#refs)) which appears to be quite similar to Jenkins’ original work (in C) which he released into the Public Domain. My contributions are a [namespace](https://archive.is/fqM9P), so that separate instances may be created; as well as helper functions to spit out random bytes, and random strings, of desired lengths. Going further, my *int32*, *double* and *range* methods expand the output options from the orginal *random* and *rand* methods; and where Rinquin extends the String object, my version uses separate functions in lieu of extending the native prototype. 5 | 6 | Since this is a CSPRNG, or alternatively, a Deterministic Random Bit Generator (DRBG), I added logic to directly perform simple [vernam](https://en.wikipedia.org/wiki/One-time_pad) (XOR) encryption. As an academic option, I created the ability to get and set the generator’s internal state. Lastly, unseeded instances will internally set themselves with a default value from [Window.crypto](https://archive.ph/4h0zE) values, which would be suitable for Monte Carlo simulations where deterministic output is not required. 7 | 8 | There are surprisingly few JavaScript examples of ISAAC. Considering it’s almost 30 years old, and has never been proven broken, one would expect more mention of it. 9 | 10 | This generator is emoji-friendly 🧐😲😊👍, which is to say that seeds, cipher keys and plaintexts are multi-byte Unicode-safe. 11 | 12 |
 
13 | Version 1.1
14 | Author: William P. "Mac" McMeans
15 | Date: 3 MAY 2018 16 |
 
17 | 18 |
 
19 | 20 |

21 | “The generation of random numbers is too important to be left to chance.”
~ Robert R. Coveyou
22 |

23 | 24 |
 
25 | 26 | ## Application: 27 | Use this to produce high-quality random numbers, and to encipher discrete messages and streams. You may also create arbitrary length byte arrays and text strings of random composition. Note: This generator is cryptographically secure. If you don’t need a secure generator then consider ALEA for your application, an RNG created by Johannes Baagøe having excellent statistical properties. 28 | 29 | 30 | ## Dependencies: 31 | None. 32 |
 
33 | 34 | 35 | ## Period: 36 | Average 28295 (not less than 240) 37 |
 
38 | 39 | 40 | ## Example usage: 41 | 42 | ``` 43 | // return an instance of the generator initialized internally with Window.crypto (Monte Carlo) 44 | > prng0 = isaacCSPRNG(); 45 | 46 | 47 | // return a 32-bit fraction in the range [0, 1] 48 | > prng0.random(); --> some random value 49 | 50 | 51 | // return an instance of the generator initialized with a specified seed (deterministic) 52 | > prng1 = isaacCSPRNG( 'this is a test' ); 53 | 54 | 55 | // return a 32-bit fraction in the range [0, 1] 56 | > prng1.random(); --> 0.9519342305138707 57 | 58 | 59 | // return a signed random integer in the range [-2^31, 2^31] 60 | > prng1.rand(); --> 2052729692 61 | 62 | 63 | // advance the generator the specified number of cycles 64 | > prng1.prng( 6 ); 65 | 66 | 67 | // return an unsigned random integer in the range [0, 2^32] 68 | > prng1.int32(); --> 288117856 69 | 70 | 71 | // return a 53-bit fraction in the range [0, 1] 72 | > prng1.double(); --> 0.4613288596233964 73 | 74 | 75 | // return 32-bit range (inclusive) // 76 | // from -27 to 400.65 77 | > prng1.range( -27, 400.625 ); --> 267.45789149729535 78 | 79 | // from 0 to 100 80 | > prng1.range( 100 ); --> 37 81 | 82 | 83 | // return an array of random bytes 84 | > prng1.bytes( 10 ); --> (10) [192, 182, 240, 253, 228, 223, 55, 207, 168, 102] 85 | 86 | 87 | // return a string of random 7-bit ASCII graphemes 88 | > prng1.chars( 10 ); --> "<3%;&mK6GH" 89 | 90 | 91 | // return vernam encryption of plaintext message, in hex format 92 | > secret = prng1.encipher( 'key', 'message', 1 ) --> "002900470041003b0021001e003f" 93 | 94 | // return vernam decryption of ciphertext message, from hex-formatted data 95 | > prng1.decipher( 'key', secret, 1 ) --> "message" 96 | 97 | 98 | // return vernam encryption of plaintext message (raw XOR) 99 | > secret = prng1.encipher( 'key', 'message' ) --> ")GA;!?" 100 | 101 | // return vernam decryption of ciphertext message 102 | > secret = prng1.encipher( 'key', secret ) --> "message" 103 | 104 | 105 | // export an object that describes the generator’s internal state 106 | > state = prng1.export(); --> JSON 107 | 108 | 109 | // import an object that will set the generator’s internal state 110 | > prng1.import( state ); 111 | 112 | 113 | // zeroize the generator 114 | > prng1.reset(); 115 | 116 | 117 | // re-seed existing generator (with a sample Gujarati phrase) 118 | > prng1.seed( 'પ્રિઝમ સાઇફર' ); 119 | 120 | 121 | > prng1.random(); --> 0.22731631994247437 122 | 123 | 124 | // re-instantiate the prng1 generator with a seed (emoji and script pseudo-alphabet) 125 | > prng1 = isaacCSPRNG( '⛄⚽🙈𝓾𝓷𝓲𝓬𝓸𝓭𝓮' ); 126 | 127 | 128 | // range parameters can be given in either order 129 | > prng1.range( 10, -20); --> -15 130 | 131 | 132 | // return ciphertext message, in hex (using Malayalam, Bengali, emoji and Unicode math symbols) 133 | > secret = prng1.encipher( '𝙠𝙚𝙮 ⚷🔑⚿ എൻക്രിപ്റ്റ് ചെയ്യുക', '𝖒𝖊𝖘𝖘𝖆𝖌𝖊 📧 📩 💌 📬 প্রিজম সাইফার', true ); --> 134 | "d810ddabd85ddda7d804ddd8d84dddeed86adde7d813ddafd842ddbe005cd810dcd70019d81fdcbf0014d803dcb20049d85cdca2004009cf09a0099b09de09ae09fe005d099f099609a209c609fd09dc" 135 | 136 | 137 | // restore the plaintext (from hex input) 138 | > prng1.decipher( '𝙠𝙚𝙮 ⚷🔑⚿ എൻക്രിപ്റ്റ് ചെയ്യുക', secret, true ); --> 139 | "𝖒𝖊𝖘𝖘𝖆𝖌𝖊 📧 📩 💌 📬 প্রিজম সাইফার" 140 | 141 | ``` 142 | NOTE: Specifiying a seed on generator instantiation, or using the seed() method, or using either of the encipher() or decipher() methods will all produce the same effect of specifically setting the generator's internal seed. In the case of enciphering/deciphering, the key provided becomes the seed. 143 |
 
144 | 145 | 146 | ## REFS: 147 | https://github.com/rubycon/isaac.js 148 | 149 | [http://www.burtleburtle.net/bob/rand/isaacafa.html](https://archive.is/sysF) 150 | 151 | [http://www.burtleburtle.net/bob/c/readable.c](https://archive.ph/5Mzx2) 152 | 153 | [http://rosettacode.org/wiki/The_ISAAC_Cipher](https://archive.ph/WEctB) 154 | 155 | https://crypto.stackexchange.com/questions/42907/why-is-isaac-not-a-pseudo-random-number-generator 156 |
 
157 | 158 | 159 | ## Tested: 160 | Google Chrome on Win 10 (x64) 161 |
 
162 | 163 | ## Version notes: 164 | * 1.1 - 3 MAY 2018
165 | ``feature`` Expose generator internal state, set/get 166 |
 
167 | * 1.0 - 22 JUL 2017
168 | ``release`` Initial release 169 |
 
170 | 171 | ## Academic papers: 172 | https://eprint.iacr.org/2006/438.pdf 173 |
 
174 | 175 | # License (BSD) 176 | Copyright (c) 2017, 2018 William McMeans 177 | 178 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 179 | 180 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 181 | 182 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 183 | 184 | 3. Neither the name of copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 185 | 186 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 187 | -------------------------------------------------------------------------------- /isaacCSPRNG-1.1.js: -------------------------------------------------------------------------------- 1 | /*/////////////////////////////////////////////////////////////////////////////////////////////////// 2 | isaacCSPRNG 1.1 3 | ///////////////////////////////////////////////////////////////////////////////////////////////////// 4 | https://github.com/macmcmeans/isaacCSPRNG/blob/master/isaacCSPRNG-1.1.js 5 | ///////////////////////////////////////////////////////////////////////////////////////////////////// 6 | This is a derivative work copyright (c) 2018, William P. "Mac" McMeans, under BSD license. 7 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 8 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | 3. Neither the name of isaacCSPRNG nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | Original work copyright (c) 2012 Yves-Marie K. Rinquin, under MIT license. 13 | https://github.com/rubycon/isaac.js 14 | ///////////////////////////////////////////////////////////////////////////////////////////////////*/ 15 | isaacCSPRNG = function( specifiedSeed ){ 16 | return (function( userSeed ) { 17 | "use strict"; 18 | 19 | /* private: internal states */ 20 | var m = new Array( 256 ) // internal memory 21 | , acc = 0 // accumulator 22 | , brs = 0 // last result 23 | , cnt = 0 // counter 24 | , r = new Array( 256 ) // result array 25 | , gnt = 0 // generation counter 26 | ; 27 | 28 | var _version = '1.1'; 29 | 30 | //////////////////////////////////////////////////// 31 | /* initial random seed */ 32 | 33 | // seed( Math.random() * 0xffffffff ); // 4294967295 34 | 35 | var internalSeed 36 | , uinta = new Uint32Array( 2 ) 37 | , defaultInternalSeed = new Array() 38 | ; 39 | window.crypto.getRandomValues( uinta ); 40 | defaultInternalSeed = uinta[ 0 ] + uinta[ 1 ]; 41 | 42 | internalSeed = userSeed || defaultInternalSeed; 43 | 44 | seed( internalSeed ); 45 | //////////////////////////////////////////////////// 46 | 47 | 48 | 49 | /* private: 32-bit integer safe adder */ 50 | function _add( x, y ) { 51 | var lsb = ( x & 0xffff ) + ( y & 0xffff ) 52 | , msb = ( x >>> 16 ) + ( y >>> 16 ) + ( lsb >>> 16 ) 53 | ; 54 | 55 | return ( msb << 16 ) | ( lsb & 0xffff ); 56 | }; 57 | 58 | 59 | 60 | /* private: return data converted from hex string */ 61 | function _hexDecode( data ){ 62 | var j 63 | , hexes = data.match(/.{1,4}/g) || [] 64 | , back = "" 65 | ; 66 | 67 | for( j = 0; j < hexes.length; j++ ) { 68 | back += String.fromCharCode( parseInt( hexes[ j ], 16 ) ); 69 | } 70 | 71 | return back; 72 | }; 73 | 74 | 75 | 76 | /* private: return data converted to hex string */ 77 | function _hexEncode( data ){ 78 | var hex 79 | , i 80 | ; 81 | 82 | var result = ""; 83 | for( i = 0; i < data.length; i++ ) { 84 | hex = data.charCodeAt( i ).toString( 16 ); 85 | result += ( "000" + hex ).slice( -4 ); 86 | } 87 | 88 | return result; 89 | }; 90 | 91 | 92 | 93 | /* private: return the CSPRNG _internals in an object (for get/set) */ 94 | function _internals() { 95 | return { 96 | a : acc 97 | , b : brs 98 | , c : cnt 99 | , m : m 100 | , r : r 101 | , g : gnt 102 | }; 103 | }; 104 | 105 | 106 | 107 | /* private: check if number is integer */ 108 | function _isInteger( n ) { 109 | return parseInt( n ) === n; 110 | }; 111 | 112 | 113 | 114 | /* private: convert string to integer array */ 115 | /* js string (ucs-2/utf16) to a 32-bit integer (utf-8 chars, little-endian) array */ 116 | function _toIntArray( string ) { 117 | var w1 118 | , w2 119 | , u 120 | , r4 = [] 121 | , r = [] 122 | , i = 0 123 | , s = string + '\0\0\0' // pad string to avoid discarding last chars 124 | , l = s.length - 1 125 | ; 126 | 127 | while( i < l ) { 128 | w1 = s.charCodeAt( i++ ); 129 | w2 = s.charCodeAt( i + 1 ); 130 | 131 | // 0x0000 - 0x007f code point: basic ascii 132 | if( w1 < 0x0080 ) { 133 | r4.push( w1 ); 134 | 135 | } else 136 | 137 | // 0x0080 - 0x07ff code point 138 | if( w1 < 0x0800 ) { 139 | r4.push( ( ( w1 >>> 6 ) & 0x1f ) | 0xc0 ); 140 | r4.push( ( ( w1 >>> 0 ) & 0x3f ) | 0x80 ); 141 | 142 | } else 143 | 144 | // 0x0800 - 0xd7ff / 0xe000 - 0xffff code point 145 | if( ( w1 & 0xf800 ) != 0xd800 ) { 146 | r4.push( ( ( w1 >>> 12 ) & 0x0f ) | 0xe0 ); 147 | r4.push( ( ( w1 >>> 6 ) & 0x3f ) | 0x80 ); 148 | r4.push( ( ( w1 >>> 0 ) & 0x3f ) | 0x80 ); 149 | 150 | } else 151 | 152 | // 0xd800 - 0xdfff surrogate / 0x10ffff - 0x10000 code point 153 | if( ( ( w1 & 0xfc00 ) == 0xd800 ) && ( ( w2 & 0xfc00 ) == 0xdc00 ) ) { 154 | u = ( ( w2 & 0x3f ) | ( ( w1 & 0x3f ) << 10 ) ) + 0x10000; 155 | r4.push( ( ( u >>> 18 ) & 0x07 ) | 0xf0 ); 156 | r4.push( ( ( u >>> 12 ) & 0x3f ) | 0x80 ); 157 | r4.push( ( ( u >>> 6 ) & 0x3f ) | 0x80 ); 158 | r4.push( ( ( u >>> 0 ) & 0x3f ) | 0x80 ); 159 | i++; 160 | 161 | } else { 162 | // invalid char 163 | } 164 | 165 | /* _add integer (four utf-8 value) to array */ 166 | if( r4.length > 3 ) { 167 | 168 | // little endian 169 | r.push( 170 | ( r4.shift() << 0 ) | ( r4.shift() << 8 ) | ( r4.shift() << 16 ) | ( r4.shift() << 24 ) 171 | ); 172 | } 173 | } 174 | 175 | return r; 176 | }; 177 | 178 | 179 | 180 | /* private: return a Vernam (XOR) transform of msg */ 181 | function _vernam( msg ) { 182 | var out = ""; 183 | 184 | for( var i = 0; i < msg.length; i++) { 185 | var ra = range( 33, 126 ); 186 | out += String.fromCharCode( ra ^ msg.charCodeAt( i ) ); 187 | } 188 | 189 | return out; 190 | }; 191 | 192 | 193 | 194 | /* public: return an array of amount elements consisting of unsigned random integers in the range [0, 255] */ 195 | function bytes( amount ) { 196 | var out = new Array( amount ); 197 | 198 | for( var i = 0; i < amount; i++ ) { 199 | out[ i ] = range( 255 ); 200 | } 201 | 202 | return out; 203 | }; 204 | 205 | 206 | 207 | /* public: return a string of length (safe) characters consisting of random 7-bit ASCII graphemes */ 208 | function chars( length ) { 209 | //var str = " ~`'\"_-+={}[]<>/\\,.:;?|!@#$%^&*()0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 210 | var str = " ~`_-+={}[]<>/,.:;?|!@#$%^&*()0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 211 | , out = '' 212 | ; 213 | 214 | for( var i = 0; i < length; i++ ) { 215 | out += str[ range( 0, str.length - 1 ) ]; 216 | } 217 | 218 | return out; 219 | }; 220 | 221 | 222 | 223 | /* public: return vernam transform on ciphertext string data/hex string data */ 224 | function decipher( key, msg, flag ) { 225 | seed( key ); 226 | 227 | if( Number( flag ) === 1 ) { 228 | return _vernam( _hexDecode( msg ) ); 229 | 230 | } else { 231 | return _vernam( msg ); 232 | } 233 | }; 234 | 235 | 236 | 237 | /* public: return a 53-bit fraction in the range [0, 1] */ 238 | function double() { 239 | return random() + ( random() * 0x200000 | 0 ) * 1.1102230246251565e-16; // 2^-53 240 | }; 241 | 242 | 243 | 244 | /* public: return vernam transform on plaintext string data/hex string data */ 245 | function encipher( key, msg, flag ) { 246 | seed( key ); 247 | 248 | if( Number( flag ) === 1 ) { 249 | return _hexEncode( _vernam( msg ) ); 250 | 251 | } else { 252 | return _vernam( msg ); 253 | } 254 | }; 255 | 256 | 257 | 258 | /* public: export object describing CSPRNG internal state */ 259 | function get() { 260 | return JSON.stringify( _internals() ); 261 | }; 262 | 263 | 264 | 265 | /* public: return an unsigned random integer in the range [0, 2^32] */ 266 | function int32() { 267 | var _r = rand(); 268 | return _r < 0 ? -_r : _r; 269 | }; 270 | 271 | 272 | 273 | /* public: expose internals */ 274 | function internals() { 275 | return { 276 | a: acc 277 | , b: brs 278 | , c: cnt 279 | , m: m 280 | , r: r 281 | }; 282 | }; 283 | 284 | 285 | 286 | /* public: isaac generator, n = number of runs */ 287 | function prng( n ){ 288 | var i 289 | , x 290 | , y 291 | ; 292 | 293 | n = ( n && typeof n === 'number' ? Math.abs( Math.floor( n ) ) : 1 ); 294 | 295 | while( n-- ) { 296 | cnt = _add( cnt, 1 ); 297 | brs = _add( brs, cnt ); 298 | 299 | for( i = 0; i < 256; i++ ) { 300 | switch( i & 3 ) { 301 | case 0: acc ^= acc << 13; break; 302 | case 1: acc ^= acc >>> 6; break; 303 | case 2: acc ^= acc << 2; break; 304 | case 3: acc ^= acc >>> 16; break; 305 | } 306 | 307 | acc = _add( m[ ( i + 128 ) & 0xff ], acc ); x = m[ i ]; 308 | m[i] = y = _add( m[ ( x >>> 2 ) & 0xff ], _add( acc, brs ) ); 309 | r[i] = brs = _add( m[ ( y >>> 10 ) & 0xff ], x ); 310 | } 311 | } 312 | }; 313 | 314 | 315 | 316 | /* public: return a signed random integer in the range [-2^31, 2^31] */ 317 | function rand() { 318 | if( !gnt-- ) { 319 | prng(); 320 | gnt = 255; 321 | } 322 | 323 | return r[ gnt ]; 324 | }; 325 | 326 | 327 | 328 | /* public: return a 32-bit fraction in the range [0, 1] */ 329 | function random() { 330 | return 0.5 + rand() * 2.3283064365386963e-10; // 2^-32 331 | }; 332 | 333 | 334 | 335 | /* public: return inclusive range */ 336 | function range() { 337 | var loBound 338 | , hiBound 339 | ; 340 | 341 | if( arguments.length === 1 ) { 342 | loBound = 0; 343 | hiBound = arguments[ 0 ]; 344 | 345 | } else { 346 | loBound = arguments[ 0 ]; 347 | hiBound = arguments[ 1 ]; 348 | } 349 | 350 | if( arguments[ 0 ] > arguments[ 1 ] ) { 351 | loBound = arguments[ 1 ]; 352 | hiBound = arguments[ 0 ]; 353 | } 354 | 355 | // return integer 356 | if( _isInteger( loBound ) && _isInteger( hiBound ) ) { 357 | return Math.floor( random() * ( hiBound - loBound + 1 ) ) + loBound; 358 | 359 | // return float 360 | } else { 361 | return random() * ( hiBound - loBound ) + loBound; 362 | } 363 | }; 364 | 365 | 366 | 367 | /* public: zeroize the CSPRNG */ 368 | function reset() { 369 | acc = brs = cnt = 0; 370 | 371 | for( var i = 0; i < 256; ++i ) { 372 | m[ i ] = r[ i ] = 0; 373 | } 374 | 375 | gnt = 0; 376 | }; 377 | 378 | 379 | 380 | /* public: seeding function */ 381 | function seed( seed ) { 382 | var a 383 | , b 384 | , c 385 | , d 386 | , e 387 | , f 388 | , g 389 | , h 390 | , i 391 | ; 392 | 393 | /* seeding the seeds of love */ 394 | a = b = c = d = e = f = g = h = 395 | 396 | /* the golden ratio ( 2654435769 ), 397 | see https://stackoverflow.com/questions/4948780/magic-number-in-boosthash-combine 398 | */ 399 | 0x9e3779b9 400 | ; 401 | 402 | if( seed && typeof seed === 'string' ) { seed = _toIntArray( seed ); } 403 | 404 | if( seed && typeof seed === 'number' ) { seed = [ seed ]; } 405 | 406 | if( seed instanceof Array ) { 407 | reset(); 408 | 409 | for( i = 0; i < seed.length; i++ ) { 410 | r[ i & 0xff ] += ( typeof seed[ i ] === 'number' ? seed[ i ] : 0 ); 411 | } 412 | } 413 | 414 | /* private: seed mixer */ 415 | function _seed_mix() { 416 | a ^= b << 11; d = _add( d, a ); b = _add( b, c ); 417 | b ^= c >>> 2; e = _add( e, b ); c = _add( c, d ); 418 | c ^= d << 8; f = _add( f, c ); d = _add( d, e ); 419 | d ^= e >>> 16; g = _add( g, d ); e = _add( e, f ); 420 | e ^= f << 10; h = _add( h, e ); f = _add( f, g ); 421 | f ^= g >>> 4; a = _add( a, f ); g = _add( g, h ); 422 | g ^= h << 8; b = _add( b, g ); h = _add( h, a ); 423 | h ^= a >>> 9; c = _add( c, h ); a = _add( a, b ); 424 | } 425 | 426 | /* scramble it */ 427 | for( i = 0; i < 4; i++ ) { _seed_mix(); } 428 | 429 | for( i = 0; i < 256; i += 8 ) { 430 | 431 | /* use all the information in the seed */ 432 | if( seed ) { 433 | a = _add( a, r[ i + 0 ] ); b = _add( b, r[ i + 1 ] ); 434 | c = _add( c, r[ i + 2 ] ); d = _add( d, r[ i + 3 ] ); 435 | e = _add( e, r[ i + 4 ] ); f = _add( f, r[ i + 5 ] ); 436 | g = _add( g, r[ i + 6 ] ); h = _add( h, r[ i + 7 ] ); 437 | } 438 | 439 | _seed_mix(); 440 | 441 | /* fill in m[] with messy stuff */ 442 | m[ i + 0 ] = a; m[ i + 1 ] = b; m[ i + 2 ] = c; m[ i + 3 ] = d; 443 | m[ i + 4 ] = e; m[ i + 5 ] = f; m[ i + 6 ] = g; m[ i + 7 ] = h; 444 | } 445 | 446 | /* do a second pass to make all of the seed affect all of m[] */ 447 | if( seed ) { 448 | for( i = 0; i < 256; i += 8 ) { 449 | a = _add( a, m[ i + 0 ] ); b = _add( b, m[ i + 1 ] ); 450 | c = _add( c, m[ i + 2 ] ); d = _add( d, m[ i + 3 ] ); 451 | e = _add( e, m[ i + 4 ] ); f = _add( f, m[ i + 5 ] ); 452 | g = _add( g, m[ i + 6 ] ); h = _add( h, m[ i + 7 ] ); 453 | 454 | _seed_mix(); 455 | 456 | /* fill in m[] with messy stuff (again) */ 457 | m[ i + 0 ] = a; m[ i + 1 ] = b; m[ i + 2 ] = c; m[ i + 3 ] = d; 458 | m[ i + 4 ] = e; m[ i + 5 ] = f; m[ i + 6 ] = g; m[ i + 7 ] = h; 459 | } 460 | } 461 | 462 | /* fill in the first set of results */ 463 | prng(); 464 | 465 | /* prepare to use the first set of results */; 466 | gnt = 256; 467 | }; 468 | 469 | 470 | 471 | /* public: import object and use it to set CSPRNG internal state */ 472 | function set( incoming ) { 473 | var imported = JSON.parse( incoming ); 474 | acc = imported.a; 475 | brs = imported.b; 476 | cnt = imported.c; 477 | m = imported.m; 478 | r = imported.r; 479 | gnt = imported.g; 480 | }; 481 | 482 | 483 | 484 | /* public: show version */ 485 | function version() { 486 | return _version; 487 | }; 488 | 489 | 490 | 491 | /* return class object */ 492 | return { 493 | 'bytes' : bytes 494 | , 'chars' : chars 495 | , 'decipher' : decipher 496 | , 'double' : double 497 | , 'encipher' : encipher 498 | , 'export' : get 499 | , 'import' : set 500 | , 'int32' : int32 501 | , 'internals' : internals 502 | , 'prng' : prng 503 | , 'rand' : rand 504 | , 'range' : range 505 | , 'random' : random 506 | , 'reset' : reset 507 | , 'seed' : seed 508 | , 'version' : version 509 | }; 510 | 511 | })( specifiedSeed ); 512 | }; 513 | -------------------------------------------------------------------------------- /isaacCSPRNG-1.1.min.js: -------------------------------------------------------------------------------- 1 | /*/////////////////////////////////////////// 2 | isaacCSPRNG 1.1 3 | https://github.com/macmcmeans/isaacCSPRNG/blob/master/isaacCSPRNG-1.1.min.js 4 | ///////////////////////////////////////////// 5 | Copyright (c) 2018, William P. "Mac" McMeans 6 | LICENSE: BSD 3-Clause License 7 | */ 8 | isaacCSPRNG=function(r){return function(r){"use strict";function n(r,n){var t=(65535&r)+(65535&n);return(r>>>16)+(n>>>16)+(t>>>16)<<16|65535&t}function t(r){return parseInt(r)===r}function e(r){for(var n="",t=0;t>>6;break;case 2:p^=p<<2;break;case 3:p^=p>>>16}p=n(h[t+128&255],p),e=h[t],h[t]=o=n(h[e>>>2&255],n(p,g)),b[t]=g=n(h[o>>>10&255],e)}}function u(){return l--||(o(),l=255),b[l]}function a(){return.5+2.3283064365386963e-10*u()}function f(){var r,n;return 1===arguments.length?(r=0,n=arguments[0]):(r=arguments[0],n=arguments[1]),arguments[0]>arguments[1]&&(r=arguments[1],n=arguments[0]),t(r)&&t(n)?Math.floor(a()*(n-r+1))+r:a()*(n-r)+r}function i(){p=g=v=0;for(var r=0;r<256;++r)h[r]=b[r]=0;l=0}function c(r){function t(){f=n(f,e^=u<<11),u=n(u,a),c=n(c,u^=a>>>2),a=n(a,f),s=n(s,a^=f<<8),f=n(f,c),p=n(p,f^=c>>>16),c=n(c,s),g=n(g,c^=s<<10),s=n(s,p),e=n(e,s^=p>>>4),p=n(p,g),u=n(u,p^=g<<8),g=n(g,e),a=n(a,g^=e>>>9),e=n(e,u)}var e,u,a,f,c,s,p,g,v;if(e=u=a=f=c=s=p=g=2654435769,r&&"string"==typeof r&&(r=function(r){for(var n,t,e,o=[],u=[],a=0,f=r+"\0\0\0",i=f.length-1;a>>6&31|192),o.push(n>>>0&63|128)):55296!=(63488&n)?(o.push(n>>>12&15|224),o.push(n>>>6&63|128),o.push(n>>>0&63|128)):55296==(64512&n)&&56320==(64512&t)&&(e=65536+(63&t|(63&n)<<10),o.push(e>>>18&7|240),o.push(e>>>12&63|128),o.push(e>>>6&63|128),o.push(e>>>0&63|128),a++),o.length>3&&u.push(o.shift()<<0|o.shift()<<8|o.shift()<<16|o.shift()<<24);return u}(r)),r&&"number"==typeof r&&(r=[r]),r instanceof Array)for(i(),v=0;v