
#include <stdio.h>
#include <string.h>

#include "sha2.h"

char *proc = "600MHz PIII";

#if defined(__GNU_LIBRARY__)
#include <sys/time.h>
typedef	struct timeval	time_str;
#define start_time(x)	gettimeofday (x, (struct timezone *) 0);

double stop_time(time_str start)
{   time_str	elapsed;
	double		t;

    gettimeofday (&elapsed, (struct timezone *) 0);
    return (elapsed.tv_sec -= start.tv_sec)
			+ 0.000001 * (elapsed.tv_usec - start.tv_usec);
}

#else

#include "windows.h"
typedef unsigned __int64	time_str;
#define start_time(x)	QueryPerformanceCounter((LARGE_INTEGER *)(x));

double stop_time(time_str start)
{	time_str	stop, freq;

	QueryPerformanceCounter((LARGE_INTEGER *)&stop);
	QueryPerformanceFrequency((LARGE_INTEGER *)&freq);
	return (stop - start) / (double)freq;
}

#endif

char* hexd = "0123456789abcdef";

void hash_out(unsigned char h[], unsigned int len)
{	unsigned char	s[200];
	unsigned int	i, d, t;
	for(i = 0, d = 0; i < len; ++i)
	{	
		if(i % 32 == 0) s[d++] = '\n';
		if(i %  8 == 0) s[d++] = ' ';
		t = h[i];
		s[d++] = hexd[t >> 4];
		s[d++] = hexd[t & 15];
	}
	s[d] = 0;
	printf(s);
}

int my_sha256(const unsigned char *s, unsigned long hv[32], unsigned int cnt, int out)
{	sha256_ctx		ht[1];
	unsigned char	h[32];
	unsigned int	i;

	sha256_begin(ht);
	for(i = 0; i < cnt; ++i)
		sha256_hash(s, strlen((const char*)s), ht);
	sha256_end(h, ht);

	if(out) hash_out(h, 32);

	return (memcmp(hv, h, 32) ? 0 : 1);

}

int my_sha384(const unsigned char *s, unsigned long hv[48], unsigned int cnt, int out)
{	sha384_ctx		ht[1];
	unsigned char	h[48];
	unsigned int	i;

	sha384_begin(ht);
	for(i = 0; i < cnt; ++i)
		sha384_hash(s, strlen((const char*)s), ht);
	sha384_end(h, ht);

	if(out) hash_out(h, 48);

	return (memcmp(hv, h, 48) ? 0 : 1);
}

int my_sha512(const unsigned char *s, unsigned long hv[64], unsigned int cnt, int out)
{	sha512_ctx		ht[1];
	unsigned char	h[64];
	unsigned int	i;

	sha512_begin(ht);
	for(i = 0; i < cnt; ++i)
		sha512_hash(s, strlen((const char*)s), ht);
	sha512_end(h, ht);

	if(out) hash_out(h, 64);

	return (memcmp(hv, h, 64) ? 0 : 1);
}

int my_sha2(const unsigned char *s, unsigned long hv[64], unsigned int cnt, unsigned int len, int out)
{	sha2_ctx		ht[1];
	unsigned char	h[64];
	unsigned int	i;

	sha2_begin(ht, len);
	for(i = 0; i < cnt; ++i)
		sha2_hash(s, strlen((const char*)s), ht);
	sha2_end(h, ht);

	i = (len > 64 ? len >> 3 : len); 
	if(out) hash_out(h, i);

	return (memcmp(hv, h, i) ? 0 : 1);
}

const unsigned char *in[5] = 
{	(const unsigned char*)"abc",
	(const unsigned char*)"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
	(const unsigned char*)"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
	(const unsigned char*)"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",
	(const unsigned char*)"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
};

#if defined(_MSC_VER)
#define rotr32(x,n)   _lrotr(x,n)
#else
#define rotr32(x,n)   (((x) >> n) | ((x) << (32 - n)))
#endif

#define bswap_32(x)	(rotr32((x), 24) & 0x00ff00ff | rotr32((x), 8) & 0xff00ff00)

#define hv(p)	0x##p

unsigned long hr256[5][8] = 
{
	{	hv(ba7816bf), hv(8f01cfea), hv(414140de), hv(5dae2223), 
		hv(b00361a3), hv(96177a9c), hv(b410ff61), hv(f20015ad)
	},
	{	hv(248d6a61), hv(d20638b8), hv(e5c02693), hv(0c3e6039), 
		hv(a33ce459), hv(64ff2167), hv(f6ecedd4), hv(19db06c1)
	},
	{	hv(cf5b16a7), hv(78af8380), hv(036ce59e), hv(7b049237), 
		hv(0b249b11), hv(e8f07a51), hv(afac4503), hv(7afee9d1)
	},
	{	hv(941ac378), hv(682e3dc6), hv(6275dd49), hv(d5fb0997), 
		hv(8754ecf4), hv(231d18d3), hv(0326fa51), hv(962648ec)
	},
	{	hv(cdc76e5c), hv(9914fb92), hv(81a1c7e2), hv(84d73e67), 
		hv(f1809a48), hv(a497200e), hv(046d39cc), hv(c7112cd0)
	}
};

unsigned long hr384[5][12] = 
{	
	{	hv(cb00753f), hv(45a35e8b), hv(b5a03d69), hv(9ac65007), 
		hv(272c32ab), hv(0eded163), hv(1a8b605a), hv(43ff5bed),
		hv(8086072b), hv(a1e7cc23), hv(58baeca1), hv(34c825a7)
	},
	{
		hv(3391fddd), hv(fc8dc739), hv(3707a65b), hv(1b470939), 
		hv(7cf8b1d1), hv(62af05ab), hv(fe8f450d), hv(e5f36bc6),
		hv(b0455a85), hv(20bc4e6f), hv(5fe95b1f), hv(e3c8452b)
	},
	{	hv(09330c33), hv(f71147e8), hv(3d192fc7), hv(82cd1b47), 
		hv(53111b17), hv(3b3b05d2), hv(2fa08086), hv(e3b0f712),
		hv(fcc7c71a), hv(557e2db9), hv(66c3e9fa), hv(91746039)
	},
	{	hv(3d208973), hv(ab3508db), hv(bd7e2c28), hv(62ba290a), 
		hv(d3010e49), hv(78c198dc), hv(4d8fd014), hv(e582823a),
		hv(89e16f9b), hv(2a7bbc1a), hv(c938e2d1), hv(99e8bea4)
	},
	{	hv(9d0e1809), hv(716474cb), hv(086e834e), hv(310a4a1c), 
		hv(ed149e9c), hv(00f24852), hv(7972cec5), hv(704c2a5b),
		hv(07b8b3dc), hv(38ecc4eb), hv(ae97ddd8), hv(7f3d8985)
	}
};

unsigned long hr512[5][16] =
{
	{	hv(ddaf35a1), hv(93617aba), hv(cc417349), hv(ae204131), 
		hv(12e6fa4e), hv(89a97ea2), hv(0a9eeee6), hv(4b55d39a),
		hv(2192992a), hv(274fc1a8), hv(36ba3c23), hv(a3feebbd), 
		hv(454d4423), hv(643ce80e), hv(2a9ac94f), hv(a54ca49f)
	},
	{	hv(204a8fc6), hv(dda82f0a), hv(0ced7beb), hv(8e08a416), 
		hv(57c16ef4), hv(68b228a8), hv(279be331), hv(a703c335),
		hv(96fd15c1), hv(3b1b07f9), hv(aa1d3bea), hv(57789ca0), 
		hv(31ad85c7), hv(a71dd703), hv(54ec6312), hv(38ca3445)
	},
	{	hv(8e959b75), hv(dae313da), hv(8cf4f728), hv(14fc143f), 
		hv(8f7779c6), hv(eb9f7fa1), hv(7299aead), hv(b6889018),
		hv(501d289e), hv(4900f7e4), hv(331b99de), hv(c4b5433a), 
		hv(c7d329ee), hv(b6dd2654), hv(5e96e55b), hv(874be909)
	},
	{	hv(930d0cef), hv(cb30ff11), hv(33b68981), hv(21f1cf3d), 
		hv(27578afc), hv(afe8677c), hv(5257cf06), hv(9911f75d),
		hv(8f5831b5), hv(6ebfda67), hv(b278e66d), hv(ff8b84fe), 
		hv(2b2870f7), hv(42a580d8), hv(edb41987), hv(232850c9)
	},
	{	hv(e718483d), hv(0ce76964), hv(4e2e42c7), hv(bc15b463), 
		hv(8e1f98b1), hv(3b204428), hv(5632a803), hv(afa973eb),
		hv(de0ff244), hv(877ea60a), hv(4cb0432c), hv(e577c31b), 
		hv(eb009c5c), hv(2c49aa2e), hv(4eadb217), hv(ad8cc09b)
	}
};

int main(void)
{	unsigned long	n_char;
	unsigned int	i, j;
	time_str		start;
	char			*ok = " ok", *e0 = " sha256 error", *e1 = " sha384 error", 
					*e2 = " sha512 error", *e3 = " sha2 error";

	for(i = 0; i < 5; ++i)
		for(j = 0; j < 8; ++j)
			hr256[i][j] = bswap_32(hr256[i][j]);

	for(i = 0; i < 5; ++i)
		for(j = 0; j < 12; ++j)
			hr384[i][j] = bswap_32(hr384[i][j]);

	for(i = 0; i < 5; ++i)
		for(j = 0; j < 16; ++j)
			hr512[i][j] = bswap_32(hr512[i][j]);

	printf("\n\nabc");
	printf("%s", (my_sha256(in[0], hr256[0], 1, 1) ? ok : e0));
	printf("%s", (my_sha2(in[0], hr256[0], 1, 32, 1) ? ok : e3));
	printf("%s", (my_sha384(in[0], hr384[0], 1, 1) ? ok : e1));
	printf("%s", (my_sha2(in[0], hr384[0], 1, 384, 1) ? ok : e3));
	printf("%s", (my_sha512(in[0], hr512[0], 1, 1) ? ok : e2));
	printf("%s", (my_sha2(in[0], hr512[0], 1, 64, 1) ? ok : e3));

	printf("\n\nabcdbcde...");
	printf("%s", (my_sha256(in[1], hr256[1], 1, 1) ? ok : e0));
	printf("%s", (my_sha2(in[1], hr256[1], 1, 32, 1) ? ok : e3));
	printf("%s", (my_sha384(in[1], hr384[1], 1, 1) ? ok : e1));
	printf("%s", (my_sha2(in[1], hr384[1], 1, 48, 1) ? ok : e3));
	printf("%s", (my_sha512(in[1], hr512[1], 1, 1) ? ok : e2));
	printf("%s", (my_sha2(in[1], hr512[1], 1, 64, 1) ? ok : e3));

	printf("\n\nabcdefghbcdefghicd...");
	printf("%s", (my_sha256(in[2], hr256[2], 1, 1) ? ok : e0));
	printf("%s", (my_sha2(in[2], hr256[2], 1, 32, 1) ? ok : e3));
	printf("%s", (my_sha384(in[2], hr384[2], 1, 1) ? ok : e1));
	printf("%s", (my_sha2(in[2], hr384[2], 1, 48, 1) ? ok : e3));
	printf("%s", (my_sha512(in[2], hr512[2], 1, 1) ? ok : e2));
	printf("%s", (my_sha2(in[2], hr512[2], 1, 64, 1) ? ok : e3));

	printf("\n\nabcdefgh....");
	printf("%s", (my_sha256(in[3], hr256[3], 1, 1) ? ok : e0));
	printf("%s", (my_sha2(in[3], hr256[3], 1, 32, 1) ? ok : e3));
	printf("%s", (my_sha384(in[3], hr384[3], 1, 1) ? ok : e1));
	printf("%s", (my_sha2(in[3], hr384[3], 1, 48, 1) ? ok : e3));
	printf("%s", (my_sha512(in[3], hr512[3], 1, 1) ? ok : e2));
	printf("%s", (my_sha2(in[3], hr512[3], 1, 64, 1) ? ok : e3));

	printf("\n\naaa....aaa (1,000,000 characters)");
	n_char = 1000000;
	printf("%s", (my_sha256(in[4], hr256[4], n_char / 50, 1) ? ok : e0));
	printf("%s", (my_sha2(in[4], hr256[4], n_char / 50, 32, 1) ? ok : e3));
	printf("%s", (my_sha384(in[4], hr384[4], n_char / 50, 1) ? ok : e1));
	printf("%s", (my_sha2(in[4], hr384[4], n_char / 50, 48, 1) ? ok : e3));
	printf("%s", (my_sha512(in[4], hr512[4], n_char / 50, 1) ? ok : e2));
	printf("%s", (my_sha2(in[4], hr512[4], n_char / 50, 64, 1) ? ok : e3));

	printf("\n\nTime (in seconds) for 100,000,000 characters on a %s", proc);
	n_char = 100000000;
	start_time(&start);
	my_sha256(in[4], hr256[4], n_char / 50, 0);
	printf("\n  SHA256: %5.2f", stop_time(start)); 
	start_time(&start);
	my_sha2(in[4], hr256[4], n_char / 50, 256, 0);
	printf("  SHA256: %5.2f", stop_time(start)); 
	
	start_time(&start);
	my_sha384(in[4], hr384[4], n_char / 50, 0);
	printf("\n  SHA384: %5.2f", stop_time(start)); 
	start_time(&start);
	my_sha2(in[4], hr384[4], n_char / 50, 384, 0);
	printf("  SHA384: %5.2f", stop_time(start)); 

	start_time(&start);
	my_sha512(in[4], hr512[4], n_char / 50, 0);
	printf("\n  SHA512: %5.2f", stop_time(start)); 
	start_time(&start);
	my_sha2(in[4], hr512[4], n_char / 50, 512, 0);
	printf("  SHA512: %5.2f", stop_time(start)); 

	printf("\n\n");
	return 0;
}
