/**
 * JEG 1.1b - a Javascript Entropy Gatherer
 * Copyright (c) 2002 Lapo Luchini <lapo@lapo.it>
 * http://www.lapo.it/JEG/
 * $Header: /usr/local/cvsroot/JEG/JEG.js,v 1.8 2002/10/20 09:20:13 lapo Exp $
 *
 * JEG is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * JEG is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with JEG; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/******** begin of Paul Johnston's SHA1 library code ********/

/*
 * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
 * in FIPS PUB 180-1
 * Version 2.0 Copyright Paul Johnston 2000 - 2002.
 * Other contributors: Greg Holt, Ydnar
 * Distributed under the Lesser GNU Public License (LGPL)
 * See http://pajhome.org.uk/crypt/md5 for details.
 */

/*
 * Calculate the SHA-1 of an array of big-endian words, and a bit length
 */
function core_sha1(x, len)
{
  /* append padding */
  x[len >> 5] |= 0x80 << (24 - len % 32)
  x[((len + 64 >> 9) << 4) + 15] = len

  var w = Array(80)
  var a =  1732584193
  var b = -271733879
  var c = -1732584194
  var d =  271733878
  var e = -1009589776

  for(var i = 0; i < x.length; i += 16)
  {
    var olda = a
    var oldb = b
    var oldc = c
    var oldd = d
    var olde = e

    for(var j = 0; j < 80; j++)
    {
      if(j < 16) w[j] = x[i + j]
      else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1)
      var t = safe_add(safe_add(rol(a, 5), ft(j, b, c, d)), 
                       safe_add(safe_add(e, w[j]), kt(j)))
      e = d
      d = c
      c = rol(b, 30)
      b = a
      a = t
    }

    a = safe_add(a, olda)
    b = safe_add(b, oldb)
    c = safe_add(c, oldc)
    d = safe_add(d, oldd)
    e = safe_add(e, olde)
  }
  return Array(a, b, c, d, e)
  
  /*
   * Perform the appropriate triplet combination function for the current
   * iteration
   */
  function ft(t, b, c, d)
  {
    if(t < 20) return (b & c) | ((~b) & d);
    if(t < 40) return b ^ c ^ d;
    if(t < 60) return (b & c) | (b & d) | (c & d);
    return b ^ c ^ d;
  }
  
  /*
   * Determine the appropriate additive constant for the current iteration
   */
  function kt(t)
  {
    return (t < 20) ?  1518500249 : (t < 40) ?  1859775393 :
           (t < 60) ? -1894007588 : -899497514;
  }  

  /*
   * Add integers, wrapping at 2^32. This uses 16-bit operations internally
   * to work around bugs in some JS interpreters.
   */
  function safe_add(x, y)
  {
    var lsw = (x & 0xFFFF) + (y & 0xFFFF)
    var msw = (x >> 16) + (y >> 16) + (lsw >> 16)
    return (msw << 16) | (lsw & 0xFFFF)
  }
  
  /*
   * Bitwise rotate a 32-bit number to the left.
   */
  function rol(num, cnt)
  {
    return (num << cnt) | (num >>> (32 - cnt))
  }
}

/*
 * Convert a string to an array of little-endian words.
 * Characters >255 have their hi-byte silently ignored.
 */
function str2binl(str)
{
  var bin = Array()
  for(var i = 0; i < str.length; i++)
    bin[i>>2] |= (str.charCodeAt(i) & 0xFF) << (i & 0x1F)
  return bin
}

/******** end of MD5 library code, begin of original JEG code ********/

var JEG = new Object();

/** entropy pool (should be able to contain 640 bit of entropy) */
JEG.pool = [
  0, 0, 0, 0, 0, //  0  1  2  3  4: pool
  0, 0, 0, 0, 0, //  5  6  7  8  9: pool
  0, 0, 0, 0, 0, // 10 11 12 13 14: pool
  0, 0, 0, 0, 0  // 15 16 17 18 19: pool
];

/** estimated entropy contained in the pool */
JEG.entropy = 0;

/** temporary buffer for data to be put ni the pool */
JEG.buffer = "";

/**
 * blk is modified in its first 16 places
 */
JEG.mix = function(blk) {
  var n = core_sha1(blk);
  var r = n[0];
  this.pool[ 0]^=n[0]; this.pool[ 1]^=n[1]; this.pool[ 2]^=n[2]; this.pool[ 3]^=n[3]; this.pool[ 4]^=n[4];
  blk[(r++)&0xF]^=n[0]; blk[(r++)&0xF]^=n[1]; blk[(r++)&0xF]^=n[2]; blk[(r++)&0xF]^=n[3]; blk[(r++)&0xF]^=n[4];
  n = core_sha1(blk);
  this.pool[ 5]^=n[0]; this.pool[ 6]^=n[1]; this.pool[ 7]^=n[2]; this.pool[ 8]^=n[3]; this.pool[ 9]^=n[4];
  blk[(r++)&0xF]^=n[0]; blk[(r++)&0xF]^=n[1]; blk[(r++)&0xF]^=n[2]; blk[(r++)&0xF]^=n[3]; blk[(r++)&0xF]^=n[4];
  n = core_sha1(blk);
  this.pool[10]^=n[0]; this.pool[11]^=n[1]; this.pool[12]^=n[2]; this.pool[13]^=n[3];this.pool[14]^=n[4];
  blk[(r++)&0xF]^=n[0]; blk[(r++)&0xF]^=n[1]; blk[(r++)&0xF]^=n[2]; blk[(r++)&0xF]^=n[3]; blk[(r++)&0xF]^=n[4];
  n = core_sha1(blk);
  this.pool[15]^=n[0]; this.pool[16]^=n[1]; this.pool[17]^=n[2]; this.pool[18]^=n[3];this.pool[19]^=n[4];
}

/**
 * Add a string's content to the pool.
 * Can also be used with a fake argument to just add the timestamp.
 */
JEG.seed = function(data, entr) {
  data = String(data);
  this.entropy += Math.min(entr, data.length << 2); // I never estime that the string can contain more than 4 bit per character
  if(this.entropy > 640)
    this.entropy = 640;
  this.buffer += data; // the passed data (hoping it contains good entropy)
  this.buffer += "/" + String((new Date()).valueOf()); // a little addition of entropy
  this.buffer += "/" + String(Math.random()); // probably no entropy here as it uses the system date, but we can lose nothing in using it
  if(window.crypt) // crypto librart usually on Netscape and Mozilla
    this.buffer += "/" + String(window.crypt.random(16)); // this should be good entropy!
  if(this.buffer.length > 1024) { // there is probably enough entropy to avoid "problems"
    this.mix(str2binl(this.buffer)); // let's pour it in
    this.buffer = "";
  }
  return true;
}

/**
 * Returns a supposedly-random 'bits'-bit integer.
 */
JEG.randomBits = function(bits) {
  if(this.buffer.length > 0) { // there is data in the this.buffer
    this.mix(str2binl(this.buffer)); // let's pour it in
    this.buffer = "";
  }
  //TODO hashare l'output
  this.pool[15]++; // increment counter
  this.pool[15]&=0xFFFF7FFF; // avoid counter carry bits
  var v = this.pool[15] & 0x3; // counter % 4
  if(v == 0) // needs to be mixed, self-feeded to stir the pool
    this.mix(this.pool.concat([])); // using concat to duplicate the array
  return this.pool[v];
}

/**
 * Returns a supposedly-random 32-bit integer.
 */
JEG.randomInt = function() {
  return this.randomBits(32);
}

/**
 * Returns a pseudo-random 32-bit integer.
 */
JEG.randomBytes = function(howMany) {
  /*TODO
  var i, l, u = new Array();
  for(i = 0, l; i < howMany; ) {
    l = this.randInt();
    u[i++] = (l >>> 24) & 0xFF;
    if(i < howMany)
      u[i++] = (l >>> 16) & 0xFF;
    if(i < howMany)
      u[i++] = (l >>> 8) & 0xFF;
    if(i < howMany)
      u[i++] = l & 0xFF;
  }
  return bytes;*/
}

