/* ***************************************************************
This is a JavaScript Library that contains a variety of functions
that support encryption efforts.  Everything from data obfuscation
functions, to Pseudo Random Number Generators, to hash functions.

There is a major effort to create alternatives to Cryptographically
Secure pseudo-random number Generators (CSGs).  I have several
examples of alternate techniques.
*************************************************************** */

/* ***** First, we have true global constants ***** */
var Hex = "0123456789abcdef";  // chars used to represent hex codes



/* This part contains global constants that the user may change to
affect the way the RASCAL system works.  Changing any of these values
will alter the encrypted output given the same keys and plain-text
input.

A good idea is to set these to your unique values before using the
RASCAL system, and then modifying them periodically. Changing a single
character or number will produce an entirely different output from the
system.
*/

/* ***************************************************************
This is a "hidden" key value that makes your encryptions unique
to you.  It makes your encryptions different from those of other
users when they use the same keyboard values against similar text.

It should have a length of about 60 characters (400 bit encryption.)
***************************************************************** */
var SubGenKey = "Febuary 2008 - This is Ron's special key value.";


/* *****************************************************************
Key-sorts may have a bucket size, such that the data is not fully
sorted.  The buckets are in order, but the data within the buckets
may not be in order.  This value MUST range from 0 to 30.  The value
is used in a shift-right statement that determines the number of
buckets for a given array size.  Length shift-right 10 means that
there will be 1,024 buckets, if possible.  For example, if I1 is 10,
and if the array size is less than 1,024, then the array is totally
ordered.  But if the array is 10,000 items, then there will be 1,024
butkets, each about 10 items long.  It gets close to ordering the
data, but saves some time in the sort.  For things like a shuffle,
it works just fine, and executes much faster.  BucketSize=length>>I1.

The larger I1, the more random the data will be.  A value of 30 will
totally mix the data.  And the smaller the I1 value, the less random
it will be.  At 8, it means that a 1,000 byte array will have
bucket sizes of about 4 items each.  Or, about 996 values of every
1,000 will be moved to a different position in the array.  That's
shuffled, in my book!
****************************************************************** */
var I1 = 5;  // sizer for buckets in a key-sort


/* ******************************************************************
In many parts of the code a starting point within an array is
calculated which is usually not the first location of the array, but is
based on some Pseudo Random value.  IN is an index that modifies this
value by adding to it.  Because of the keys given to an encryption, we
may calculate that we shall begin with the 10th element of an array. 
If IN is 2 this will be modified by starting with the 12th element of
that array instead.

Any numerical value may be used because modulo math will size it
properly, but I would keep it under about 1,000.

The longer your message is, or your keys are, the more obfuscation
this value will perform.
****************************************************************** */
IN = 13;  // value used to modify index into an array


/* ******************************************************************
These constants control the additive factor per key entry in the key
formation algorithms within Rand7, Rand8 and Rand11.  They should be
prime, and lie between 23 and 101.  If you are going to enforce
really long keys, then they should be smaller.  These values are one
of the ways the code knows the difference in an "a" in key position
14, and an "a" in key position 15.  These values totally change key
evaluation and make key order important.
****************************************************************** */
var C1 = 23;   // additive key factor for Rand7
var C2 = 29;   // additive key factor for Rand8
var C3 = 37;   // additive key factor for Rand11


/* *****************************************************************
In JavaScript, all numeric values are 16 decimal-digit values.  To
help in the conversion to other languages I specify the range of
values that variables may take (as coded).
  (b) = byte. (8-bits).  Usually a numeric value.
  (c) = JavaScript character value (UTF may convert to u32).
  (i..) = signed integer that requires some number of places.
          (i16 means a 16-bit signed integer.)
  (u..) = unsigned integer requiring some number of places.
  (fp) = floating point value.  IEEE standard, usually.

In compiled languages it is more efficient to specify smaller values.
For example, with just minor changes all (fp) values can be changed
to (u32) values, which would execute much faster, and require less
space for the object.
*************************************************************** */


/* ***************************************************************
This code converts character strings to ordinal values (numbers).
s is a string (in JavaScript) and the output is a u32 array (UTF).
**************************************************************** */
function Conv (s) {  // convert string to numeric data (c)
var i,ls=s.length;            // (u32)
var a = new Array ();         // ordinal value array (b)
  for (i=0; i<ls; i++)        // run the string
    a[i] = s.charCodeAt(i);   // the JS ordinal value function
  return a;                   // th-th-that's all, folks.
}

/* *****************************************************************
Within normal text data there may appear special UTF codes with a
value beyond 8-bits.  Because the encryption code works only with 8-bit
values, we must convert these special UTF codes into a series of 8-bit
groups, and then convert back to UTF after decryption.  We use special
marker-bytes to mark these converted strings of bytes.
***************************************************************** */
function FixUTF (a) {  /* fix UTF data in a - array in, array out
  1 = 1 byte special marker storage
  2 = 2 bytes stored
  3 = 3 bytes
  4 = 4 bytes
*/
var i,j=0,t,la=a.length;         // (i32)
var a2 = new Array();            // (b)
  for (i=0; i<la; i++) {         // scan data for weird values
    t = a[i];                    // get an ordinal value
    if (t < 5) {                 // special char to protect
      a2[j++]=1;  // special marker char to be protected follows
      a2[j++]=t;  // marker char
    } 
    else if (t < 256)
      a2[j++] = t;               // normal text data, all done
    else if (t < 65536) {        // small UTF stuff (most codes)
      a2[j++] = 2;               // marker
      a2[j++] = (t & 0xff00) >> 8;
      a2[j++] =  t & 0xff;
    }
    else {                       // big UTF stuff
      a2[j++] = 4;               // marker
      a2[j++] = (t & 0xff000000) >>> 24;
      a2[j++] = (t & 0xff0000) >> 16;
      a2[j++] = (t & 0xff00) >> 8;
      a2[j++] =  t & 0xff;
    }
  }
  return a2;              // return an array
}

function RstUTF (a) {  // restore UTF codes - numbers in, chars out
var i=0,j=0,k,c,t,la=a.length;
var a1=new Array();    // output array
  do {                 // run the array
    t = a[i++];        // current value
    if (t < 5) {       // special marker present?
      c = t;           // bytes to follow
      t = 0;           // running total
      for (k=0; k<c; k++)
        t=(t << 8) | a[i++];  // form big UTF number
    }
    a1[j++] = String.fromCharCode(t);  // put UTF back into data
  } while (i<la);
  return a1.join("");  // return string
}

/* ******************************************************************
This will shuffle a byte array according to generated random numbers.
A key-sort is performed where the key is a random value, and the data
array is the data to be shuffled.  When the random values are ordered,
the data array has then been randomized.  This is a better randomizer
than shuffle1, but it takes quite a bit longer because of the sort.
****************************************************************** */
function Shuffle (aray,seed,r) {  // shuffle an entire numerical array
/* aray = the array of ordinal data to shuffle. (b)
   seed = some numeric array used to seed the shuffle keys (b)
   r    - if not zero, then init PRNG to new value. (b) */
var k = new Array ();             // sort key value (fp)
var i,la=aray.length;             // (i32)
  if (r != 0) Rand11(seed);       // init PRNG
  for (i=0; i<la; i++)
    k[i] = Rand11();              // fill shuffle key
  QuickSortK(aray,k,0,la-1,la>>I1); // shuffle aray with key sort
  return aray;                    // aray is now in random order
}

function UnShuffle (aray,seed) {  // undo shuffle of vals
var ary1 = new Array ();          // output array (b)
var a = new Array ();             // (i32)
var k = new Array ();             // (fp)
var i,la=aray.length;             // (i32)
  Rand11(seed);                   // init RNG
  for (i=0; i<la; i++){           // create original key data
    a[i] = i;                     // location index
    k[i] = Rand11();              // shuffle key
  }
  QuickSortK(a,k,0,la-1,la>>I1);  // recreate the shuffle
  for (i=0; i<la; i++)            // put cards back where they were
    ary1[a[i]] = aray[i];
  return ary1;                    // return original order
}

/* ****************************************************************
These two routines will shuffle and unshuffle data in arithmetic,
rather than geometric times.  They are MUCH faster than a key sort!
But not as thorough in the shuffle.  Works best if seed is hashed.
***************************************************************** */
function Shuffle1 (aray, seed) {  // shuffle aray based on seed
var i,j,k,la=aray.length,ls=seed.length,ck=0,tmp;  // (u32)
var s1 = new Array ();            // the mixer state array  (u32)
var ary1 = new Array ();          // output array (b)
  for (i=0; i<la; i++)            // init index schedule
    s1[i] = i;
  for (i=0; i<ls; i++)            // arithmetic checksum
    ck = ck + seed[i];
  j=ck+ls+IN; k=ck+la;            // starting vals
  for (i=0; i<la; i++) {          // mix index using seed
    j = (j + s1[i] + seed[k++ % ls]) % la;
    tmp=s1[i]; s1[i]=s1[j]; s1[j]=tmp;  
  }
  for (i=0; i<la; i++)            // shuffle 'em up
    ary1[i] = aray[s1[i]];
  return ary1;
}

function UnShuffle1 (aray, seed) {// unshuffle aray based on seed
var s1 = new Array ();
var ary1 = new Array ();
var i,j,k,la=aray.length,ls=seed.length,ck=0,tmp;
  for (i=0; i<la; i++)            // init index schedule
    s1[i] = i;
  for (i=0; i<ls; i++)            // arithmetic checksum
    ck = ck + seed[i];
  j=ck+ls+IN; k=ck+la;            // starting vals
  for (i=0; i<la; i++)  {         // repeat the mixing in s1
    j = (j + s1[i] + seed[k++ % ls]) % la;
    tmp=s1[i]; s1[i]=s1[j]; s1[j]=tmp;
  }
  for (i=0; i<la; i++)            // put back where they belong
    ary1[s1[i]] = aray[i];
  return ary1;
}

/* ****************************************************************
Normal text is only 7-bit data which leaves the high-order bit of
the key exposed.  These two functions work with a substitution array
to make it full 8-bit data.
   aray = the array of ordinal data to have substitution applied
   seed = some numeric byte array used to build the substitution table
 This function will build a substitution array to be used to force
 the data to be encrypted into a full 8-bit version.

 Best fed with a 256-byte hashed seed.
****************************************************************** */
function SubGen (aray, seed) {         // substitute char set gen
var ary1 = new Array ();               // temp working array (u32)
var i,la=aray.length,k=Rand15(seed);   // (i32)
  for (i=0; i<256; i++)                // base index
    ary1[i]=(i+k)&255;
  ary1 = Shuffle1(ary1, seed);         // mix it up
  for (i=0; i<la; i++) {               // replace characters
    k = (k + Rand15()) & 255;          // random rotate of sub array
    aray[i] = ary1[(aray[i]+k)&255];   // sub value
  }
  return aray;
}

function UnSubGen (aray, seed) {       // undo substitute chars
var ary1 = new Array ();               // temp working arrays
var ary3 = new Array ();               // (b)
var i,la=aray.length,k=Rand15(seed);   // (i32)
  for (i=0; i<256; i++)
    ary3[i]=(i+k)&255;
  ary3 = Shuffle1(ary3, seed);
  for (i=0; i<256; i++)                // form unsub array
    ary1[ary3[i]] = i;
  for (i=0; i<la; i++) {               // remove substitution
    k = (k + Rand15()) & 255;          // rotate sub array
    aray[i] = (ary1[aray[i]]-k)&255;   // original value back
  }
  return aray;
}

/* ***************************************************************
  This will randomly shuffle the bits within an array of bytes.
  This can be very time-comsuming for large amounts of data - if
  it takes too long then switch to BitShuffle1, which is faster,
  but not quite as good.
*************************************************************** */
function BitShuffle (a,seed,r) {  // shuffle some bits in array
var i,j,l=0,la=a.length,m,n=0;    // (i32)
var b  = new Array ();            // bit array
  for (i=0; i<la; i++) {          // run the array for bits
    m = a[i];                     // an 8-bit byte
    for (j=0; j<8; j++) {         // process the byte
      b[l++] = (m >> 7) & 1;      // bits to be shuffled
      m = m << 1;                 // to pick up next bit
    }
  }
  b = Shuffle(b,seed,r);          // shuffle the bits
  for (i=0; i<la; i++) {          // reconstruct the array
    m = 0;
    for (j=0; j<8; j++)
      m = (m << 1) | b[n++];
    a[i] = m;
  }
  return a;
}

function UnBitShuffle (a,seed) {  // Undo what BitShuffle did
var i,j,l=0,la=a.length,m,n=0;    // (i32)
var b  = new Array ();            // bit array
  for (i=0; i<la; i++) {          // run the array for bits
    m = a[i];                     // an 8-bit byte
    for (j=0; j<8; j++) {         // process the byte
      b[l++] = (m >> 7) & 1;      // bits to be unshuffled
      m = m << 1;                 // to pick up next bit
    }
  }
  b = UnShuffle(b,seed);          // unmix the bits
  for (i=0; i<la; i++) {          // reconstruct the array
    m = 0;
    for (j=0; j<8; j++)
      m = (m << 1) | b[n++];
    a[i] = m;
  }
  return a;
}

/* ***************************************************************
  This is quite a bit faster because it does not do the quicksort.
*************************************************************** */
function BitShuffle1(a,seed) {    // shuffle some bits in array
var i,j,k=0,l=0,la=a.length,m;    // (i32)
var b = new Array ();             // bit array (b)
  for (i=0; i<la; i++) {          // turn array into bits
    m = a[i];
    for (j=0; j<8; j++) {
      b[k++] = (m >> 7) & 1;
      m = m << 1;
    }
  }
  b = Shuffle1(b,seed);           // shuffle the bits
  for (i=0; i<la; i++) {          // rebuild the array bytes
    m = 0;
    for (j=0; j<8; j++)
      m = (m << 1) | b[l++];
    a[i] = m;
  }
  return a;
}

function UnBitShuffle1(a,seed) {  // Undo what BitShuffle did
var i,j,k=0,l=0,la=a.length,m;    // (i32)
var b  = new Array ();            // bit array
  for (i=0; i<la; i++) {          // run the array for bits
    m = a[i];
    for (j=0; j<8; j++) {
      b[k++] = (m >> 7) & 1;
      m = m << 1;
    }
  }
  b = UnShuffle1(b,seed);         // unmix the bits
  for (i=0; i<la; i++) {          // reconstruct the array
    m = 0;
    for (j=0; j<8; j++)
      m = (m << 1) | b[l++];
    a[i] = m;
  }
  return a;
}

/* ******************************************************************
   This is a special sort that just puts data into buckets no larger
   than x. The buckets are ordered (every element within bucket 1 is
   equal to or less than every element within bucket 2), but the data
   within the buckets may not be ordered.
   Used as irreversible mixer of data.
****************************************************************** */
function QuickSort1 (a,left,right,x) { // recursive quicksort
var t;                                       // (b)
var l=left,r=right;                          // (i32)
var c=(a[l]+a[r])/2;                         // center value (fp)
  do {
    while ((a[l] < c) && (l < right)) l=l+1; // find val above center
    while ((c < a[r]) && (left < r))  r=r-1; // find val below center
    if (l <= r) {                            // still in current box?
      t=a[l]; a[l]=a[r]; a[r]=t;             // exchange items
      l=l+1; r=r-1;                          // adjust indexes
    }
  } while (l <= r);                          // until we're turn
  if (left < r-x)  QuickSort1(a,left,r,x);   // recursive calls
  if (l < right-x) QuickSort1(a,l,right,x);
  return a;
}

/* *******************************************************************
   This is a key-sort that sorts a on the key k, and puts results
   into ordered buckets of a size no larger than x.  Shuffler.
   The smaller x is, the more thorough the shuffle of a.
******************************************************************** */
function QuickSortK (a,k,left,right,x) { // recursive, key-quicksort
var t,l=left,r=right;                        // (i32)
var h;                                       // (fp)
var c=(k[l]+k[r])/2;                         // center value (fp)
  do {
    while ((k[l] < c) && (l < right)) l=l+1; // find val above center
    while ((c < k[r]) && (left < r))  r=r-1; // find val below center
    if (l <= r) {                            // still in current box?
      h=k[l]; k[l]=k[r]; k[r]=h;             // exchange the key
      t=a[l]; a[l]=a[r]; a[r]=t;             // exchange the data
      l=l+1; r=r-1;                          // adjust indexes
    }
  } while (l <= r);                          // until we're thru
  if (left < r-x)  QuickSortK(a,k,left,r,x); // recursive calls
  if (l < right-x) QuickSortK(a,k,l,right,x);
  return a;
}

/* ******************************************************************
  This will echo a prime, or return the next lower prime value.
****************************************************************** */
function Prime (tst) {
var i=3,tp;                 // (i32)
  if ((tst & 1) == 0) tst = tst - 1;  // force to odd
  if (tst < 8) return tst;  // already prime
  tp = Math.sqrt(tst+1);    // no need to go beyond this value
  while (i < tp) {
    if ((tst % i) == 0) {   // oops, divisible
      tst = tst - 2;
      i = 3;
      continue;             // start loop over
    }
    i = i + 2;              // test next value
  }
  return tst;               // this is a prime
}

/* ***************************************************************
   Here are some hash routines that are used in various places. 
   This is a hash template for the design of your own hash.
****************************************************************** */
function Hash0 (aray,len,flg) {  // hash template
var ary1 = new Array ();         // internal place for character hash
var ary3 = new Array ();         // output array
var i,j,k,m,la=aray.length;
                          /* initialization */
  if (len > 4096) len = 4096;        // for internal protection
  if (len < 10) len = 10;
  k = 0;                             // 1st data value to use
  for (i=0; i<len; i++) ary1[i] = 0; // Initialization Value (IV)
                       /* actual hash function */
// do it len values at a time, and force to multiple of len
  m = Math.floor((la+len-1)/len)*len;  // just do calculation once
  for (i=0; i<m; i=i+len) {
// now we operate on a group of len characters (a block, if you want)
    for (j=0; j<len; j++) {      // current block of len chars
      ary1[j]=ary1[j]^aray[k++ % la]; // get chars
// Here is where we modify the ary1 block...
    }
  }
                              /* output */
  if (flg == 0) return ary1;     // 0-256 numeric output
  j = 0;                         // output array index
  for (i=0; i<len; i++) {        // hex format
    ary3[j]   = Hex.charAt(ary1[i]/16);  // get hex chars from string
    ary3[j+1] = Hex.charAt(ary1[i]%16);
    j = j + 2;                   // bump index
  }
  return ary3.join("");          // this is a len-char hash of aray
}

/* *******************************************************************
This hash function is quite a bit more sophisticated than it may
appear.  The Initial Value (IV) contains the length of the input
array, bits are shifted around within and among bytes, a sort is used
as an irreversible component, the hashed value is thoroughly
shuffled, and is lightly encrypted.

Of particular interest is that the shifting and shuffling are not the
same for any two values to be hashed - it is based on a stream of
random numbers generated from the aray being hashed. This ain't a toy!
******************************************************************* */
function Hash2 (aray,len,flg) {  // souped-up hash function
var ary1 = new Array ();         // internal place for data hash (b)
var ary3 = new Array ();         // output array (b)
var i,j,k,m,la=aray.length;      // (i32)
                          /* initialization */
  if (len == 0) len = la;             // for unknown lengths
  if (len > 4096) len = 4096;         // for internal protection
  if (len < 10) len = 10;             // at least 10 long
  k = Math.floor(Rand11(aray)*la)+IN; // 1st data val from aray
  for (i=0; i<len; i++)               // set the base of the IV
    ary1[i]=(i+k+(Rand11()*131072))&255; // base key schedule
  ary1[len>>2] = (la>>8)&255;         // insert length
  ary1[len>>1] = la&255;
  QuickSort1(ary1,0,len-1,len>>1);    // non-reversible
  ary1 = Shuffle(ary1,0,0);           // mix up Initial Value
                       /* actual hash function */
// do it len values at a time, and force to multiple of len
  m = Math.floor((la+len-1)/len)*len; // calc just once 
  for (i=0; i<m; i=i+len) {           // run input array
// now we operate on a group of len characters (a block, if you want)
    for (j=0; j<len; j++)
      ary1[j]=ary1[j]^aray[k++ % la]; // xor-in next values
    QuickSort1(ary1,0,len-1,len>>1);  // non-reversible
    ary1 = BitShuffle(ary1,0,0);      // mix up the bits
  }
  QuickSort1(ary1,0,len-1,len>>1);    // non-reversible
  ary1 = BitShuffle(ary1,0,0);        // shuffle them bits
                              /* output */
  if (flg == 0) return ary1;     // 0-255 numeric output
  j = 0;                         // output array index
  for (i=0; i<len; i++) {        // hex format
    ary3[j]   = Hex.charAt(ary1[i]/16);  // get hex chars from string
    ary3[j+1] = Hex.charAt(ary1[i]%16);
    j = j + 2;                   // bump index
  }
  return ary3.join("");          // this is a len-char hash of aray
}


/* **************************************************************** 
  An assortment of pseudo random number genreators.

  I use different generators that are not mathematically related, as
  much as possible, to be certain of generating non-related sequences.

  Non-related sequences used together are almost impossible to break.

  LCGs produce a base run for the LFGs upon which the actual seed is
  impressed.  3 and 9 are the LCGs.  1 is a special cascade LCG of my
  design that gives more deference to the seed.  14 and 15 are
  versions of the old RC4 system, tightened up just a bit.

  Do not ignore the lite encryptors of Shift, Shuffle and SubGen,
  above.  They are not toys.  And Hash2 deals very well with hiding
  keys.  This library provides a wealth of tools for obfuscating data.
***************************************************************** */


/* **************************************************************
   This will encrypt data with a uniformly distributed key.  This
   function will both encrypt and decrypt the data with same seed.
   In this function, the block is the entire text message.
   Dist1 uses Shuffle1 and is much faster, but it is not as random.
*************************************************************** */
function Dist (aray,seed) {
var a  = new Array ();       // arrays for data & key (b)
var la = aray.length;        // length of input array (i32)
var i,cnt=Math.floor((la+255)/256)*256; // (i32)
  for (i=0; i<cnt; i++)      // base key schedule
    a[i] = (i+la+IN) & 255;  // encryption keys
  a = Shuffle(a,seed,1);     // key sort to mix a
  for (i=0; i<la; i++)       // encrypt/decrypt the array
    aray[i]=aray[i]^a[i];
  return aray;
}

function Dist1 (aray,seed) { // encrypt with even dist of vals
var a  = new Array ();       // array for data (b)
var la = aray.length;        // length of input array (i32)
var i,cnt=Math.floor((la+255)/256)*256; // (i32)
  for (i=0; i<cnt; i++)      // base key schedule
    a[i] = (i+la+IN) & 255;  // encryption keys
  a = Shuffle1(a,seed);      // shuffle the values
  for (i=0; i<la; i++)       // encrypt/decrypt the array
    aray[i]=aray[i]^a[i];
  return aray;
}

/* ****************************************************************
  This function promises an equal number of 1 and 0 bits in the
  keys applied to the message.  Dist operates at the byte level,
  but Even operates at the bit level.
**************************************************************** */
function Even (aray,seed) {  // encrypt with even dist of bits
var a  = new Array ();       // array for key (b)
var i,la = aray.length;      // (i32)
  for (i=0; i<la; i++)       // base key schedule
    a[i] = 85;               // encryption keys (85=01010101)
  a = BitShuffle(a,seed,1);  // to mix bits in a
  for (i=0; i<la; i++)       // encrypt/decrypt the array
    aray[i]=aray[i]^a[i];
  return aray;
}

function Even1 (aray,seed) { // encrypt with even dist of bits
var a  = new Array ();       // array for key (b)
var i,la = aray.length;      // (i32)
  for (i=0; i<la; i++)       // base key schedule
    a[i] = 85;               // encryption keys (85=01010101)
  a = BitShuffle1(a,seed);   // shuffle the values
  for (i=0; i<la; i++)       // encrypt/decrypt the array
    aray[i]=aray[i]^a[i];
  return aray;
}

/* ****************************************************************
This gets close to a Cryptographically Secure (CS) generator.
This is a work in progress.  I think it is "secure" because there
is no way to tell which of the 512+ generators are called on to
produce output.
**************************************************************** */
var d1    = new Array (); // place for digits
var r1    = 0;            // circular carry value (remaindering)
var dcnt1 = 512;          // min number of digits (changes)
var dmod1 = 536870879;    // max digit size - near power of 2
var dmul1 =   2587639;    // multiplier (smaller than max, & prime)

function Rand1 (seed) {
var i,j,t,m,t1;
  if (arguments.length > 0) {        // seed present?
var ls = seed.length;
    dcnt1 = Prime(Math.max(512,ls)+Math.floor(Rand7(seed)*512));
    r1 = Rand7()*dmul1;              // initial remainder value
    j = Math.floor(Rand7() * dcnt1); // mess up index into seed
    for (i=dcnt1-1; i>=0; i--)       // base key
      d1[i] = Rand7() * dmod1;
    d1 = Shuffle1(d1,seed);          // shuffle base before use
    for (i=0; i<dcnt1; i++)          // stuff seed over random digits
      d1[i]=d1[i] + (seed[j++ % ls] * 4194305);
    for (i=0; i<dcnt1+j; i++) Rand1(); // recursive discard and mixer
  }
  t1=Math.floor(Rand7()*dcnt1);      // which generator to use
  t = d1[t1] * dmul1 + r1;           // multiply a digit, and add carry
  m = t % dmod1;                     // remainder(lower digits)
  d1[t1] = m;                        // calc new array value
  r1 = t / dmod1;                    // the carry value...
  return m / dmod1;                  // the return value...
}

/* ******************************************************************
Alternating Step LFSR.  Surprisingly hard to crack.
****************************************************************** */
function Rand2a (a,seed) {
var h1,h2,i,la=a.length;
  h1 = Rand7(seed) * 256;
  h2 = Rand11(seed) * 256;
  Rand8(seed);
  for (i=0; i<la; i++) {
    if (Rand8() < .5) h1 = Rand7() * 256;
    else h2 = Rand11() * 256;
    a[i] = a[i] ^ h1 ^ h2;
  }
  return a;
}

/* ******************************************************************
Shrinking LFSR generator.  Surprisingly hard to crack.
****************************************************************** */
function Rand2s (a,seed) {
var i,la=a.length;
  Rand8(seed);
  Rand11(seed);
  for (i=0; i<la; i++) {
    while (Rand8() > .5) 
      Rand11();
    a[i] = a[i] ^ (Rand11() * 256);
  }
  return a;
}

/* ******************************************************************
Self-Shrinking LFSR generator.  Surprisingly hard to crack.
****************************************************************** */
function Rand2ss (a,seed) {
var i,h,la=a.length;
  Rand8(seed);
  for (i=0; i<la; i++) {
   do
     h = Rand8();
   while (h >= .5);
   a[i] = a[i] ^ (h * 512);   // encrypt with 0-255
  }
  return a;
}

/* **************************************************************** */

var d3    =   1234567;        // number < 10^9
var dmod3 = 536870849;        // depth = dmod - 1
var dmul3 =   2317493;

function Rand3 (seed) {       // very simple random number generator
var t;
  if (arguments.length > 0) { // seed present?
    d3 = seed;                // prime the seed
    Rand3(); Rand3();         // recursive call to chuck 1st values
  }
  t = d3 * dmul3 + 1;         // very simple algorithm
  d3 = t % dmod3;             // only take lower digits (remainder)
  return d3 / dmod3;          // value between zero and one
}

/* **************************************************************** */
var d7    = new Array ();    // place for digits
var cntr7 = 0;               // times called
var dcnt7 = 521;             // minimum number of digits
var dmod7 = 281474976710597; // max size (prime, near power of 2)

function Rand7 (seed) {      // Additive lagged fibonacci generator
var i,j,t,m,n,r7=2271;
  if (arguments.length > 0) {       // seed present?
var ls = seed.length;
    for (i=0; i<ls; i++)            // calc seed
      r7 = r7 + (i+C1) * Math.E * seed[i];
    while (r7 > 1000000000) r7 = r7 / 10.1;
    dcnt7 = Prime(Math.max(521,ls));
    j = Math.floor(Rand3(r7) * dcnt7); 
    cntr7 = j + dmod7;
    for (i=0; i<dcnt7; i++) d7[i] = Rand3()*dmod7;
    d7 = Shuffle1(d7,seed);
    for (i=dcnt7-1; i>=0; i--)      // stuff seed on random digits
      d7[i]=d7[i] + (seed[j++ % ls] * 
        (2199023255552 + 33554432 + 1));
    for (i=0; i<dcnt7+j; i++) Rand7();  // recursive discard and mixer
  }
  n = cntr7--;
  t = d7[(n+362)%dcnt7]+d7[(n+520)%dcnt7];
  m = t % dmod7;
  d7[(n+520) % dcnt7] = m;          // feedback
  return m / dmod7;
}

/* *************************************************************
The user seed value is very important in this generator.  The
seed should be hashed before being fed into this function.
************************************************************* */
var d8    = new Array ();  // place for digits
var r8    = 0;             // seed for random digits
var cntr8 = 0;             // times called
var dcnt8 = 521;           // minimum number of digits
var dmod8 = 562949953421201;

function Rand8 (seed) {    // multiplicative lagged fibonacci generator
var i,j,t,m,n;
  if (arguments.length > 0) {       // seed present?
var ls = seed.length;
    r8 = 389;                       // init
    for (i=0; i<ls; i++)            // calc seed
      r8 = r8 + (i+C2) * Math.E * seed[i];
    while (r8 > 1000000000) r8 = r8 / 10.1;
    dcnt8 = Prime(Math.max(521,ls));
    j = Math.floor(Rand9(r8) * dcnt8); 
    cntr8 = j + dmod8;
    for (i=0; i<dcnt8; i++)         // prime the pump
      d8[i] = Rand9()*dmod8;
    d8 = Shuffle1(d8,seed);         // mix up the base
    for (i=dcnt8-1; i>=0; i--)      // stuff seed on random digits
      d8[i] = d8[i] + seed[j++ % ls]*(65536 + 1 + 1/127);
    for (i=0; i<dcnt8+j; i++) Rand8();  //Recursive discard
  }
  n = cntr8--;                      // index into state array
  t=(d8[(n+352)%dcnt8]*d8[(n+520)%dcnt8]);
  m = t % dmod8;
  d8[(n+520) % dcnt8] = m;                // feedback
  return m / dmod8;                 // value between 0 and 1..
}

/* ***************************************************************** 
   Random number generator support functions.  This is the base
   generator for Rand11.  Rand9 is the base generator which
   "primes" that generator.
   This is just another keep-honest routine.
******************************************************************* */
var d9    =        1234547;    // number < dmod9
var dmod9 = Math.pow(2,32);    // depth = dmod - 1
var dmul9 =        1664525;

function Rand9 (seed) {        // very simple random number generator
var t;
  if (arguments.length > 0) {  // seed present?
    d9 = seed;                 // prime the seed
    Rand9(); Rand9();          // recursive call to chuck 1st value
  }
  t = d9 * dmul9 + 1013904223; // very simple algorithm
  d9 = t % dmod9;              // only take lower digits
  return d9 / dmod9;           // value between zero and one...
}

/* ****************************************************************
It is used over a simple LCG because it has more than one cycle
of values (the LCG has but a single cycle of values), and it generates
more values before it begins to repeat for any given key.  Ir also has
15 decimal digits of accuracy, which may be JavaScript specific.
***************************************************************** */

var d11    = new Array ();    // place for digits
var cntr11 = 0;               // index into shift register
var dcnt11 = 521;             // number of digits (and keyboard seeds)
var dmod11 = 562949953421231; // max size (prime, near power of 2)

function Rand11 (seed) {      // additive lagged fibonacci generator
var i,j,t,r11,m,n;
  if (arguments.length > 0) {      // seed present?
var ls = seed.length;
    r11 = 697;                     // init
    for (i=0; i<ls; i++)           // value based on the seed
      r11 = r11 + (i+C3) * Math.PI * seed[i];
    while (r11 > 1000000000) r11 = r11 / 10.1;  // safety
    dcnt11 = Prime(Math.max(521,ls));
    j = Math.floor(Rand9(r11) * dcnt11);
    cntr11 = j + dmod11 + IN;
    for (i=dcnt11-1; i>=0; i--)    // base key
      d11[i] = Rand9() * dmod11;
    d11 = Shuffle1(d11,seed);      // shuffle base before use
    for (i=0; i<dcnt11; i++)       // stuff seed over random digits
      d11[i]=d11[i] + (seed[j++ % ls] *
        (4398046511104 + 33554432 + 1));
    for (i=0; i<dcnt11+j; i++) Rand11();  // recursive discard & mixer
  }
  n = cntr11--;                    // address, then shift right
  t=d11[(n+167)%dcnt11]+d11[(n+520)%dcnt11];
  m = t % dmod11;
  d11[(n+520)%dcnt11] = m;         // feedback
  return m / dmod11;               // return new value from 0 to 1.
}

/* ************************************************************
This is a base version of RC4 (unaltered).  It is as described,
but with the single exception that I include a Shuffle of the
key base with an asterisked comment.  Once you understand this
simple algorithm, it is very easy to modify, as I did with Rand15,
below.  Have fun with it.  I also make a few other comments.
And I modified the code a bit for speed (tmp)...  (Forgive me.)

For maximum effectiveness you should hash keys to a length of
256 characters.  That makes it very effective for keys smaller
than about 700 keyboard characters.  But Rand15 takes over for
larger key lengths up to about 8,000 keyboard characters.  Use
them both and you have iron-clad protection, and you don't have
to worry about the size of the key ("seed", in this routine.)
************************************************************* */
var d14 = new Array ();        // main key array
var i14, j14;                  // indexes into d14 array

function Rand14 (seed) {       // RC4 stream cypher
var i,j,k,tmp;
  if (arguments.length > 0) {  // args present?
var ls = seed.length;
    for (i=0; i<256; i++)      // init the key schedule algorithm
      d14[i] = i;
    d14 = Shuffle1(d14,seed);  // *** addition to mix IV ***
    j = d14[ls-1];             // *** index into key array ***
    k = d14[0];                // *** index into seed array ***
    for (i=0; i<256; i++) {    // 2nd mix using the seed
      tmp = d14[i];            // set to swap keys
      j = (j + tmp + seed[k++ % ls]) & 255;
      d14[i] = d14[j];
      d14[j] = tmp;
    }
    i14 = k;                   // *** init indexes ***
    j14 = j;                   // ***  ***
    for (i=0; i<1000+j; i++) Rand14(); // *** recursive discard ***
  }
  i14 = (i14 + 1) & 255;       // generate indexes
  tmp = d14[i14];              // remember for swap, coming up
  j14 = (j14 + tmp) & 255;
  d14[i14] = d14[j14];
  d14[j14] = tmp;
  return d14[(d14[i14] + tmp) & 255];  // value from 0 to 255
}

/* *********************************************************** */
/* This is a super-strong version of RC4. */
var d15 = new Array ();        // main key array
var dcnt15;                    // length of d15 array
var i15, j15;                  // indexes into d15 array

function Rand15 (seed) {       // Super RC4-like cipher
var i,k,tmp;
  if (arguments.length > 0) {  // args present?
var ls = seed.length;
    dcnt15 = Math.floor((ls+255)/256)*256; // mod 256
    for (i=0; i<dcnt15; i++)   // init key schedule
      d15[i] = i;
    d15 = Shuffle1(d15,seed);  // 1st mix of keys using seed
    j15 = d15[ls-1];           // index into key array
    k   = d15[0];              // index into seed array
    for (i=0; i<dcnt15; i++) { // mix keys another way
      tmp = d15[i];            // set for swap
      j15 = (j15 + tmp + seed[k++ % ls]) % dcnt15;
      d15[i] = d15[j15];
      d15[j15] = tmp;
    }
    i15 = j15;                 // init index
    for (i=0; i<dcnt15+j15; i++) Rand15(); // recursive discard
  }
  i15 = (i15 + 1) % dcnt15;    // generate indexes
  tmp = d15[i15];              // set for swap
  j15 = (j15 + tmp) % dcnt15;  //  second index
  d15[i15] = d15[j15];         //  swap them suckers
  d15[j15] = tmp;
  return d15[(d15[i15] + tmp) % dcnt15] & 255;  // value from 0 to 255
}
