//  Entropy collection utilities

/* Start by declaring static storage and initialise the entropy vector
from the time we come through here. */

// Collected entropy data
var entropydata=new Array();

// Keyboard array data length
var edlen=0;

// Start entropy collection with page load time
addEntropyTime();

// Roll milliseconds into initial entropy
ce();

// Add a byte to the entropy vector
function addEntropyByte(b) {
   entropydata[edlen++]=b;
}


/* Capture entropy. When the user presses a key or performs various
other events for which we can request notification, add the time in
255ths of a second to the entropydata array. The name of the function is
short so it doesn't bloat the form object declarations in which it
appears in various "onXXX" events. */
function ce() {
   addEntropyByte(Math.floor((((new Date).getMilliseconds()) * 255) / 999));
}

// Add a 32 bit quantity to the entropy vector
function addEntropy32(w) {
   var i;
   for (i=0; i < 4; i++) {
      addEntropyByte(w & 0xFF);
      w >>= 8;
   }
}


/* Add the current time and date (milliseconds since the epoch,
truncated to 32 bits) to the entropy vector. */
function addEntropyTime() {
   addEntropy32((new Date()).getTime());
}


/* Start collection of entropy from mouse movements. The argument
specifies the number of entropy items to be obtained from mouse motion,
after which mouse motion will be ignored.  Note that you can re-enable
mouse motion collection at any time if not already underway. */
var mouseMotionCollect=0;

// For saving and restoring mouse move handler in IE4
var oldMoveHandler;

function mouseMotionEntropy(maxsamp) {
   if (mouseMotionCollect <= 0) {
      mouseMotionCollect=maxsamp;
      if ((document.implementation.hasFeature("Events", "2.0")) && document.addEventListener) {

	 //  Browser supports Document Object Model (DOM) 2 events
	 document.addEventListener("mousemove", mouseMoveEntropy, false);
      } else {
	 if (document.attachEvent) {

	    //  Internet Explorer 5 and above event model
	    document.attachEvent("onmousemove", mouseMoveEntropy);
	 } else {

	    //	Internet Explorer 4 event model
	    oldMoveHandler=document.onmousemove;
	    document.onmousemove=mouseMoveEntropy;
	 }
      }
   }
}


/* Collect entropy from mouse motion events.  Note that this is craftily
coded to work with either DOM2 or Internet Explorer style events. Note
that we don't use every successive mouse movement event. Instead, we XOR
the three bytes collected from the mouse and use that to determine how
many subsequent mouse movements we ignore before capturing the next one.
*/

// Delay counter for mouse entropy collection
var mouseEntropyTime=0;

function mouseMoveEntropy(e) {
   if (!e) {
      e=window.event;	    // Internet Explorer event model
   }
   if (mouseMotionCollect > 0) {
      if (mouseEntropyTime-- <= 0) {
	 addEntropyByte(e.screenX & 0xFF);
	 addEntropyByte(e.screenY & 0xFF);
	 ce();
	 mouseMotionCollect--;
	 mouseEntropyTime=(entropydata[edlen - 3] ^ entropydata[edlen - 2] ^ entropydata[edlen - 1]) % 19;
      }
      if (mouseMotionCollect <= 0) {
	 if (document.removeEventListener) {
	    document.removeEventListener("mousemove", mouseMoveEntropy, false);
	 } else if (document.detachEvent) {
	    document.detachEvent("onmousemove", mouseMoveEntropy);
	 } else {
	    document.onmousemove=oldMoveHandler;
	 }
      }
   }
}

function getentropy() {
   var i, j, k=[];
   for (i=0; i < edlen; i += 2) {
      k[i/2]=entropydata[i];
   }
   i=i/2;
   for (j=1; j < edlen; j += 2) {
      k[i]=entropydata[j];
      i=i + 1;
   }
   return k;
}
