/**
 * SHA1
 * 
 * An ActionScript 3 implementation of Secure Hash Algorithm, SHA-1, as defined
 * in FIPS PUB 180-1
 * Copyright (c) 2007 Henri Torgemane
 * 
 * Derived from:
 * 		A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
 * 		in FIPS PUB 180-1
 * 		Version 2.1a Copyright Paul Johnston 2000 - 2002.
 * 		Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * 
 * See LICENSE.txt for full license information.
 */
package com.hurlant.crypto.hash
{
	

	public class SHA1 extends SHABase implements IHash
	{
		public static const HASH_SIZE:int = 20;
		
		public override function getHashSize():uint {
			return HASH_SIZE;
		}
		
		protected override function core(x:Array, len:uint):Array
		{
		  /* append padding */
		  x[len >> 5] |= 0x80 << (24 - len % 32);
		  x[((len + 64 >> 9) << 4) + 15] = len;
		
		  var w:Array = [];
		  var a:uint =  0x67452301; //1732584193;
		  var b:uint = 0xEFCDAB89; //-271733879;
		  var c:uint = 0x98BADCFE; //-1732584194;
		  var d:uint = 0x10325476; //271733878;
		  var e:uint = 0xC3D2E1F0; //-1009589776;
		
		  for(var i:uint = 0; i < x.length; i += 16)
		  {
		  	
		    var olda:uint = a;
		    var oldb:uint = b;
		    var oldc:uint = c;
		    var oldd:uint = d;
		    var olde:uint = e;
		
		    for(var j:uint = 0; j < 80; j++)
		    {
		      if (j < 16) {
		      	w[j] = x[i + j] || 0;
		      } else {
		      	w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
		      }
		      var t:uint = rol(a,5) + ft(j,b,c,d) + e + w[j] + kt(j);
		      e = d;
		      d = c;
		      c = rol(b, 30);
		      b = a;
		      a = t;
		    }
			a += olda;
			b += oldb;
			c += oldc;
			d += oldd;
			e += olde;
		  }
		  return [ a, b, c, d, e ];
		
		}
		
		/*
		 * Bitwise rotate a 32-bit number to the left.
		 */
		private function rol(num:uint, cnt:uint):uint
		{
		  return (num << cnt) | (num >>> (32 - cnt));
		}
		
		/*
		 * Perform the appropriate triplet combination function for the current
		 * iteration
		 */
		private function ft(t:uint, b:uint, c:uint, d:uint):uint
		{
		  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
		 */
		private function kt(t:uint):uint
		{
		  return (t < 20) ? 0x5A827999 : (t < 40) ?  0x6ED9EBA1 :
		         (t < 60) ? 0x8F1BBCDC : 0xCA62C1D6;
		}
		public override function toString():String {
			return "sha1";
		}
	}
}
