/*!
 *   Copyright CertainKey Inc. 2002
 */
var state=[0,0,0,0, 0,0,0,0],
    count=[0,0],
    buf=[],
    PADDING="";
buf[127] = 0;
PADDING = "\200";
for (var i=1; i<128; i++) PADDING += String.fromCharCode(0);

function F(x) { return (x + 4294967296) % 4294967296; }
function e0(x) { return (((x>>>2)|(x<<30)) ^ ((x>>>13)|(x<<19)) ^ ((x>>>22)|(x<<10))); }
function e1(x) { return (((x>>>6)|(x<<26)) ^ ((x>>>11)|(x<<21)) ^ ((x>>>25)|(x<<7))); }
function s0(x) { return (((x>>>7)|(x<<25)) ^ ((x>>>18)|(x<<14)) ^ (x >>> 3)); }
function s1(x) { return (((x>>>17)|(x<<15)) ^ ((x>>>19)|(x<<13)) ^ (x >>> 10)); }

var K = [ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
];

function sha256Xform(state, input) {
  var a,b,c,d,e,f,g,h,
      t1, t2;
  var W = [], i;

  W[15] = 0;
  for (i=0; i<16; i++) {
    t1  = (input[(4*i)  ] & 0xff); t1<<=8;
    t1 |= (input[(4*i)+1] & 0xff); t1<<=8;
    t1 |= (input[(4*i)+2] & 0xff); t1<<=8;
    t1 |= (input[(4*i)+3] & 0xff);
    W[i] = t1;
  }

  for (i=16; i<64; i++)
    W[i] = F(s1(W[i-2]) + W[i-7] + s0(W[i-15]) + W[i-16]);

  a=state[0];  b=state[1];  c=state[2];  d=state[3];
  e=state[4];  f=state[5];  g=state[6];  h=state[7];

  for (i=0; i<64; i++) {
    t1 = F(h + e1(e) + ((e & f) ^ (~e & g)) + K[i] + W[i]);
    t2 = F(e0(a) + ((a & b) ^ (a & c) ^ (b & c)));
    h = g;   g = f;   f = e;   e = F(d + t1);
    d = c;   c = b;   b = a;   a = F(t1 + t2);
  }
  state[0]=F(state[0]+a);   state[1]=F(state[1]+b);   state[2]=F(state[2]+c);   state[3]=F(state[3]+d);
  state[4]=F(state[4]+e);   state[5]=F(state[5]+f);   state[6]=F(state[6]+g);   state[7]=F(state[7]+h);

  for (i=0; i<64; i++)
    W[i] = 0;
  a = b = c = d = e = f = g = h = t1 = t2 = 0;
}

function sha256Init() {
  state[0] = 0x6a09e667;
  state[1] = 0xbb67ae85;
  state[2] = 0x3c6ef372;
  state[3] = 0xa54ff53a;
  state[4] = 0x510e527f;
  state[5] = 0x9b05688c;
  state[6] = 0x1f83d9ab;
  state[7] = 0x5be0cd19;
  count[0] = count[1] = 0;

  for (var i=0; i<128; i++)
    buf[i] = 0;
}

function sha256Update(input, inputLen) {
  var i, j, index, partLen, temp=[];

  temp[4*16-1] = 0;

  index = ((count[0] >>> 3) & 0x3f);

  if ((count[0] += (inputLen << 3)) < (inputLen << 3)) {
    count[1]++;
    count[1] += (inputLen >>> 29);
  }

  partLen = 64 - index;

  if (inputLen >= partLen) {
    for (j=0; j<partLen; j++)
      buf[index + j] = input.charCodeAt(j); 
    sha256Xform(state, buf);

    for (i=partLen; i+63<inputLen; i+=64) {
      for (j=0; j<4*16; j++)
        temp[j] = input.charCodeAt(i + j);
      sha256Xform(state, temp);
    }
    for (j=0; j<4*16; j++)
      temp[j] = 0;

    index = 0;
  } else {
    i = 0;
  }

  for (j=0; j<inputLen-i; j++) {
    buf[index + j] = input.charCodeAt(i + j);
  }
}

function sha256Final(digest) {
  var bits="", index, padLen, t, i;

  t = count[1];
  bits += String.fromCharCode((t>>>24)&0xff);
  bits += String.fromCharCode((t>>>16)&0xff);
  bits += String.fromCharCode((t>>> 8)&0xff);
  bits += String.fromCharCode((t     )&0xff);
  t = count[0];
  bits += String.fromCharCode((t>>>24)&0xff);
  bits += String.fromCharCode((t>>>16)&0xff);
  bits += String.fromCharCode((t>>> 8)&0xff);
  bits += String.fromCharCode((t     )&0xff);

  index = (count[0] >>> 3) & 0x3f;
  padLen = (index < 56) ? (56 - index) : ((64+56) - index);
  sha256Update(PADDING, padLen);

  sha256Update(bits, 8);

  for (i=0; i<8; i++) {
    t = state[i];
    digest[4*i+3] = (t & 0xff); t>>>=8;
    digest[4*i+2] = (t & 0xff); t>>>=8;
    digest[4*i+1] = (t & 0xff); t>>>=8;
    digest[4*i  ] = (t & 0xff);
  }

  for (i=0; i<8; i++)
    state[i] = 0;
  count[0] = count[1] = 0;
  for (i=0; i<128; i++)
    buf[i] = 0;
}

function hex8(n) { return hex_(n,8); }
function hex(n) { return hex_(n,2); }
function hex_(n,l) {
  var ret ="",
      z = [0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f'];
  for (var i=0; i<l; i++) {
    ret = z[n%16] +ret;
    n >>>= 4;
  }
  return ret;
}

function sha256(str) {
  var res=[]; res[8*4-1]=0;
  sha256Init();
  sha256Update(str, str.length);
  sha256Final(res);
  X="";
  for (i=0; i<8*4; i++) X += hex(res[i]);
  return X;
}
