#ifndef SHA
#define SHA 1

//void SHA256(uint4 *restrict state0,uint4 *restrict state1, const uint4 block0, const uint4 block1, const uint4 block2, const uint4 block3, bool notfresh){
//void SHA256(uint*restrict state, uint*restrict block, bool notfresh){

uint8 SHA256(uint8 restrict digest, uint16 restrict block){

    uint A = digest.s0;
    uint B = digest.s1;
    uint C = digest.s2;
    uint D = digest.s3;
    uint E = digest.s4;
    uint F = digest.s5;
    uint G = digest.s6;
    uint H = digest.s7;
	uint W0x = block.s0;
	uint W0y = block.s1;
	uint W0z = block.s2;
	uint W0w = block.s3;
    uint W1x = block.s4;
    uint W1y = block.s5;
    uint W1z = block.s6;
    uint W1w = block.s7;
    uint W2x = block.s8;
    uint W2y = block.s9;
    uint W2z = block.s10;
    uint W2w = block.s11;
    uint W3x = block.s12;
    uint W3y = block.s13;
    uint W3z = block.s14;
    uint W3w = block.s15;
    uint T0x = A;
    uint T0y = B;
    uint T0z = C;
    uint T0w = D;
    uint T1x = E;
    uint T1y = F;
    uint T1z = G;
    uint T1w = H;

	uint K0, K1, K2, K3, K4, K5, K6, K7;

	if(notfresh){
		K0 = K[0];
		K1 = K[1];
		K2 = K[2];
		K3 = K[3];
		RND(A,B,C,D,E,F,G,H, W0x + K0);
		RND(H,A,B,C,D,E,F,G, W0y + K1);
		RND(G,H,A,B,C,D,E,F, W0z + K2);
		RND(F,G,H,A,B,C,D,E, W0w + K3);
	}else{
		K0 = K[63];
		K1 = K[64];
		K2 = K[65];
		K3 = K[66];
		K4 = K[67];
        K5 = K[68];
        K6 = K[69];
        K7 = K[70];

		D = K0 + W0x;
		H = K1 + W0x;
		C = K2 + Tr1(D) + Ch(D, K3, K4) + W0y;
		G = K5 + C + Tr2(H) + Ch(H, K6, K7);
		T1x = K3;
		T1y = K4;
        K4 = K[71];
        K5 = K[72];
        K6 = K[73];
        K7 = K[74];
        K0 = K[75];
		B = K4 + Tr1(C) + Ch(C,D,K3) + W0z;
		F = K5 + B + Tr2(G) + Maj(G,H, K6);
		A = K7 + Tr1(B) + Ch(B,C,D) + W0w;
		E = K0 + A + Tr2(F) + Maj(F,G,H);

		//save K constants for fresh condition
		T0x = K6;
		T0y = K[77];
		T0z = K[78];
		T0w = K[79];

		T1z = K[80];
		T1w = K[81];
	}

    K0 = K[4];
    K1 = K[5];
    K2 = K[6];
    K3 = K[7];
    K4 = K[8];
    K5 = K[9];
    K6 = K[10];
    K7 = K[11];

	RND(E,F,G,H,A,B,C,D, W1x + K0);
	RND(D,E,F,G,H,A,B,C, W1y + K1);
	RND(C,D,E,F,G,H,A,B, W1z + K2);
	RND(B,C,D,E,F,G,H,A, W1w + K3);

	RND(A,B,C,D,E,F,G,H, W2x + K4);
	RND(H,A,B,C,D,E,F,G, W2y + K5);
	RND(G,H,A,B,C,D,E,F, W2z + K6);
	RND(F,G,H,A,B,C,D,E, W2w + K7);

    K7 = K[76];
    K0 = K[12];
    K1 = K[13];
    K2 = K[14];
    K3 = K[15];
    K4 = K[16];
    K5 = K[17];
    K6 = K[18];

	RND(E,F,G,H,A,B,C,D, W3x + K0);
	RND(D,E,F,G,H,A,B,C, W3y + K1);
	RND(C,D,E,F,G,H,A,B, W3z + K2);
	RND(B,C,D,E,F,G,H,A, W3w + K7);


	W0x += Wr1(W3z) + W2y + Wr2(W0y);
	RND(A,B,C,D,E,F,G,H, W0x + K3);
	W0y += Wr1(W3w) + W2z + Wr2(W0z);
	RND(H,A,B,C,D,E,F,G, W0y + K4);
	W0z += Wr1(W0x) + W2w + Wr2(W0w);
	RND(G,H,A,B,C,D,E,F, W0z + K5);
	W0w += Wr1(W0y) + W3x + Wr2(W1x);
	RND(F,G,H,A,B,C,D,E, W0w + K6);

    K0 = K[19];
    K1 = K[20];
    K2 = K[21];
    K3 = K[22];
    K4 = K[23];
    K5 = K[24];
    K6 = K[25];
    K7 = K[26];

	W1x += Wr1(W0z) + W3y + Wr2(W1y);
	RND(E,F,G,H,A,B,C,D, W1x + K0);
	W1y += Wr1(W0w) + W3z + Wr2(W1z);
	RND(D,E,F,G,H,A,B,C, W1y + K1);
	W1z += Wr1(W1x) + W3w + Wr2(W1w);
	RND(C,D,E,F,G,H,A,B, W1z + K2);
	W1w += Wr1(W1y) + W0x + Wr2(W2x);
	RND(B,C,D,E,F,G,H,A, W1w + K3);

	W2x += Wr1(W1z) + W0y + Wr2(W2y);
	RND(A,B,C,D,E,F,G,H, W2x + K4);
	W2y += Wr1(W1w) + W0z + Wr2(W2z);
	RND(H,A,B,C,D,E,F,G, W2y + K5);
	W2z += Wr1(W2x) + W0w + Wr2(W2w);
	RND(G,H,A,B,C,D,E,F, W2z + K6);
	W2w += Wr1(W2y) + W1x + Wr2(W3x);
	RND(F,G,H,A,B,C,D,E, W2w + K7);

    K0 = K[27];
    K1 = K[28];
    K2 = K[29];
    K3 = K[30];
    K4 = K[31];
    K5 = K[32];
    K6 = K[33];
    K7 = K[34];

	W3x += Wr1(W2z) + W1y + Wr2(W3y);
	RND(E,F,G,H,A,B,C,D, W3x + K0);
	W3y += Wr1(W2w) + W1z + Wr2(W3z);
	RND(D,E,F,G,H,A,B,C, W3y + K1);
	W3z += Wr1(W3x) + W1w + Wr2(W3w);
	RND(C,D,E,F,G,H,A,B, W3z + K2);
	W3w += Wr1(W3y) + W2x + Wr2(W0x);
	RND(B,C,D,E,F,G,H,A, W3w + K3);

	W0x += Wr1(W3z) + W2y + Wr2(W0y);
	RND(A,B,C,D,E,F,G,H, W0x + K4);
	W0y += Wr1(W3w) + W2z + Wr2(W0z);
	RND(H,A,B,C,D,E,F,G, W0y + K5);
	W0z += Wr1(W0x) + W2w + Wr2(W0w);
	RND(G,H,A,B,C,D,E,F, W0z + K6);
	W0w += Wr1(W0y) + W3x + Wr2(W1x);
	RND(F,G,H,A,B,C,D,E, W0w + K7);

    K0 = K[35];
    K1 = K[36];
    K2 = K[37];
    K3 = K[38];
    K4 = K[39];
    K5 = K[40];
    K6 = K[41];
    K7 = K[42];

	W1x += Wr1(W0z) + W3y + Wr2(W1y);
	RND(E,F,G,H,A,B,C,D, W1x + K0);
	W1y += Wr1(W0w) + W3z + Wr2(W1z);
	RND(D,E,F,G,H,A,B,C, W1y + K1);
	W1z += Wr1(W1x) + W3w + Wr2(W1w);
	RND(C,D,E,F,G,H,A,B, W1z + K2);
	W1w += Wr1(W1y) + W0x + Wr2(W2x);
	RND(B,C,D,E,F,G,H,A, W1w + K3);

	W2x += Wr1(W1z) + W0y + Wr2(W2y);
	RND(A,B,C,D,E,F,G,H, W2x + K4);
	W2y += Wr1(W1w) + W0z + Wr2(W2z);
	RND(H,A,B,C,D,E,F,G, W2y + K5);
	W2z += Wr1(W2x) + W0w + Wr2(W2w);
	RND(G,H,A,B,C,D,E,F, W2z + K6);
	W2w += Wr1(W2y) + W1x + Wr2(W3x);
	RND(F,G,H,A,B,C,D,E, W2w + K7);

    K0 = K[43];
    K1 = K[44];
    K2 = K[45];
    K3 = K[46];
    K4 = K[47];
    K5 = K[48];
    K6 = K[49];
    K7 = K[50];

	W3x += Wr1(W2z) + W1y + Wr2(W3y);
	RND(E,F,G,H,A,B,C,D, W3x + K0);
	W3y += Wr1(W2w) + W1z + Wr2(W3z);
	RND(D,E,F,G,H,A,B,C, W3y + K1);
	W3z += Wr1(W3x) + W1w + Wr2(W3w);
	RND(C,D,E,F,G,H,A,B, W3z + K2);
	W3w += Wr1(W3y) + W2x + Wr2(W0x);
	RND(B,C,D,E,F,G,H,A, W3w + K3);

	W0x += Wr1(W3z) + W2y + Wr2(W0y);
	RND(A,B,C,D,E,F,G,H, W0x + K4);
	W0y += Wr1(W3w) + W2z + Wr2(W0z);
	RND(H,A,B,C,D,E,F,G, W0y + K5);
	W0z += Wr1(W0x) + W2w + Wr2(W0w);
	RND(G,H,A,B,C,D,E,F, W0z + K6);
	W0w += Wr1(W0y) + W3x + Wr2(W1x);
	RND(F,G,H,A,B,C,D,E, W0w + K7);

    K0 = K[51];
    K1 = K[52];
    K2 = K[53];
    K3 = K[54];
    K4 = K[55];
    K5 = K[56];
    K6 = K[57];
    K7 = K[58];

	W1x += Wr1(W0z) + W3y + Wr2(W1y);
	RND(E,F,G,H,A,B,C,D, W1x + K0);
	W1y += Wr1(W0w) + W3z + Wr2(W1z);
	RND(D,E,F,G,H,A,B,C, W1y + K1);
	W1z += Wr1(W1x) + W3w + Wr2(W1w);
	RND(C,D,E,F,G,H,A,B, W1z + K2);
	W1w += Wr1(W1y) + W0x + Wr2(W2x);
	RND(B,C,D,E,F,G,H,A, W1w + K3);

	W2x += Wr1(W1z) + W0y + Wr2(W2y);
	RND(A,B,C,D,E,F,G,H, W2x + K4);
	W2y += Wr1(W1w) + W0z + Wr2(W2z);
	RND(H,A,B,C,D,E,F,G, W2y + K5);
	W2z += Wr1(W2x) + W0w + Wr2(W2w);
	RND(G,H,A,B,C,D,E,F, W2z + K6);
	W2w += Wr1(W2y) + W1x + Wr2(W3x);
	RND(F,G,H,A,B,C,D,E, W2w + K7);

    K4 = K[59];
    K5 = K[60];
    K6 = K[61];
    K7 = K[62];

	W3x += Wr1(W2z) + W1y + Wr2(W3y);
	RND(E,F,G,H,A,B,C,D, W3x + K4);
	W3y += Wr1(W2w) + W1z + Wr2(W3z);
	RND(D,E,F,G,H,A,B,C, W3y + K5);
	W3z += Wr1(W3x) + W1w + Wr2(W3w);
	RND(C,D,E,F,G,H,A,B, W3z + K6);
	W3w += Wr1(W3y) + W2x + Wr2(W0x);
	RND(B,C,D,E,F,G,H,A, W3w + K7);

	A += T0x;
	B += T0y;
	C += T0z;
	D += T0w;
	E += T1x;
	F += T1y;
	G += T1z;
	H += T1w;
    //state[0] = A;
    //state[1] = B;
    //state[2] = C;
    //state[3] = D;
    //state[4] = E;
    //state[5] = F;
    //state[6] = G;
    //state[7] = H;

	digest.s0 = A;
	digest.s0 = B;
	digest.s0 = C;
	digest.s0 = D;
	digest.s0 = E;
	digest.s0 = F;
	digest.s0 = G;
	digest.s0 = H;

	return digest;
}
