    //  Entropy collection utilities

    /*	Start by declaring static storage and initialise
    	the entropy vector from the time we come through
    	here. */
	
    var entropyData = new Array();   	    // Collected entropy data
    var edlen = 0;  	    	    	    // Keyboard array data length
 
    addEntropyTime();	    	    	    // Start entropy collection with page load time
    ce();   	    	    	    	    // Roll milliseconds into initial entropy

    //	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;
    var oldMoveHandler;     	    // For saving and restoring mouse move handler in IE4
	
    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;
		}
	    }
//dump("Mouse enable", mouseMotionCollect);
	}
    }
    
    /*	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.  */
	
    var mouseEntropyTime = 0;	    // Delay counter for mouse entropy collection
	
    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;
//dump("Mouse Move", byteArrayToHex(entropyData.slice(-3)));
    	    }
	    if (mouseMotionCollect <= 0) {
	    	if (document.removeEventListener) {
		    document.removeEventListener("mousemove", mouseMoveEntropy, false);
		} else if (document.detachEvent) {
		    document.detachEvent("onmousemove", mouseMoveEntropy);
		} else {
		    document.onmousemove = oldMoveHandler;
		}
//dump("Spung!", 0);
	    }
	}
    }    
    
    /*	Compute a 32 byte key value from the entropy vector.
    	We compute the value by taking the MD5 sum of the even
	and odd bytes respectively of the entropy vector, then
	concatenating the two MD5 sums.  */
    
    function keyFromEntropy() {
	var i, k = new Array(32);
	
	if (edlen == 0) {
	    alert("Blooie!  Entropy vector void at call to keyFromEntropy.");
	}
//dump("Entropy bytes", edlen);

	md5_init();
	for (i = 0; i < edlen; i += 2) {
	    md5_update(entropyData[i]);
	}
	md5_finish();
    	for (i = 0; i < 16; i++) {
	    k[i] = digestBits[i];
	}

	md5_init();
	for (i = 1; i < edlen; i += 2) {
	    md5_update(entropyData[i]);
	}
	md5_finish();
    	for (i = 0; i < 16; i++) {
	    k[i + 16] = digestBits[i];
	}
	
//dump("keyFromEntropy", byteArrayToHex(k));
	return k;
    }
