/*
The Keccak sponge function, designed by Guido Bertoni, Joan Daemen,
Michaël Peeters and Gilles Van Assche. For more information, feedback or
questions, please refer to our website: http://keccak.noekeon.org/

Implementation by Ronny Van Keer,
hereby denoted as "the implementer".

To the extent possible under law, the implementer has waived all copyright
and related or neighboring rights to the source code in this file.
http://creativecommons.org/publicdomain/zero/1.0/
*/

#include "Keccak-compact8.h"

#define cKeccakR_SizeInBytes    (cKeccakR / 8)
#include "crypto_hash.h"
#ifndef crypto_hash_BYTES
    #ifdef cKeccakFixedOutputLengthInBytes
        #define crypto_hash_BYTES cKeccakFixedOutputLengthInBytes
    #else
        #define crypto_hash_BYTES cKeccakR_SizeInBytes
    #endif
#endif

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

const char	testVectorMessage[] = 
	"\x3A\x3A\x81\x9C\x48\xEF\xDE\x2A\xD9\x14\xFB\xF0\x0E\x18\xAB\x6B\xC4\xF1\x45\x13\xAB\x27\xD0\xC1\x78\xA1\x88\xB6\x14\x31\xE7\xF5"
	"\x62\x3C\xB6\x6B\x23\x34\x67\x75\xD3\x86\xB5\x0E\x98\x2C\x49\x3A\xDB\xBF\xC5\x4B\x9A\x3C\xD3\x83\x38\x23\x36\xA1\xA0\xB2\x15\x0A"
	"\x15\x35\x8F\x33\x6D\x03\xAE\x18\xF6\x66\xC7\x57\x3D\x55\xC4\xFD\x18\x1C\x29\xE6\xCC\xFD\xE6\x3E\xA3\x5F\x0A\xDF\x58\x85\xCF\xC0"
	"\xA3\xD8\x4A\x2B\x2E\x4D\xD2\x44\x96\xDB\x78\x9E\x66\x31\x70\xCE\xF7\x47\x98\xAA\x1B\xBC\xD4\x57\x4E\xA0\xBB\xA4\x04\x89\xD7\x64"
	"\xB2\xF8\x3A\xAD\xC6\x6B\x14\x8B\x4A\x0C\xD9\x52\x46\xC1\x27\xD5\x87\x1C\x4F\x11\x41\x86\x90\xA5\xDD\xF0\x12\x46\xA0\xC8\x0A\x43"
	"\xC7\x00\x88\xB6\x18\x36\x39\xDC\xFD\xA4\x12\x5B\xD1\x13\xA8\xF4\x9E\xE2\x3E\xD3\x06\xFA\xAC\x57\x6C\x3F\xB0\xC1\xE2\x56\x67\x1D"
	"\x81\x7F\xC2\x53\x4A\x52\xF5\xB4\x39\xF7\x2E\x42\x4D\xE3\x76\xF4\xC5\x65\xCC\xA8\x23\x07\xDD\x9E\xF7\x6D\xA5\xB7\xC4\xEB\x7E\x08"
	"\x51\x72\xE3\x28\x80\x7C\x02\xD0\x11\xFF\xBF\x33\x78\x53\x78\xD7\x9D\xC2\x66\xF6\xA5\xBE\x6B\xB0\xE4\xA9\x2E\xCE\xEB\xAE\xB1";

#if        (cKeccakB    == 1600) && (cKeccakR == 1024)

const char	testVectorSqueezed[] = 
	"\x94\x35\xFC\x67\x1D\xFC\xFC\xDA\xC1\x49\x27\x7E\x2C\xAA\xA8\x0E\xD3\xD4\xA2\x35\x93\x00\xDB\x89\x2B\x80\x93\xDF\xFA\x94\x42\xBB\x5C\x08\xF2\x42\xF2\xFC\x2C\xB5\xF8\x38\x80\x32\x29\x9F\x1D\xF4\x7A\x57\x48\x9A\x4F\xC0\xD6\x6D\x88\xE4\x83\x09\x23\x20\xA4\x71\x89\x7F\xB6\xAD\xE6\x78\x97\xE5\x13\x8C\x45\xF1\x91\x74\xA4\xB1\xAE\x0E\x51\x0F\xA3\x90\x82\x5D\x17\x56\x89\x89\xC3\x65\x9F\xC5\x7B\x93\x45\xD7\xD9\x3E\xE5\x88\xCB\x26\x29\xC5\x77\x08\x08\x19\x52\x57\xBB\xF4\x2B\x06\x95\x76\xD9\x40\x11\x98\x9D\xC6\xEB\xC4";

const char	testVectorAccumulated[] = 
	"\x82\xCE\xAA\x06\xEE\x14\x0F\x60\xEC\x60\x19\x58\x23\x9A\x74\xB5\x70\xF6\xDC\x5B\x73\xC0\xCB\xD4\x23\x2B\xAA\x45\xD7\x18\x1C\x93\x08\x7A\x6A\x4E\xD3\x87\x9C\x1E\xC7\xDA\x28\x51\x20\x7D\x54\x9D\x01\x71\x3B\xFF\x05\x88\xDB\x3A\xBC\x0D\xA6\xE1\xE4\xC5\xD2\x17\x8D\xB8\x43\xD8\xA9\x06\xF4\xA6\x1B\x28\x6B\x13\xC5\xC3\x39\x8E\xB6\xD2\x3C\x4F\x1C\xDD\xD3\x96\x01\xE5\x1F\xE4\x6C\x91\x5D\x09\xCF\xC3\x48\xED\x02\x2F\xC8\x85\x0B\xE5\x2E\x56\x17\xFC\xE3\xA7\xE3\xD0\x54\x48\x75\x28\xFD\x8D\xF6\xA3\x1F\x8C\x73\x8D\xC4\x79";

#elif    (cKeccakB    == 1600) && (cKeccakR == 1152)

const char	testVectorSqueezed[] = 
	"\x5A\xF5\x69\x87\xEA\x9C\xF1\x1F\xCD\x0E\xAC\x5E\xBC\x14\xB0\x37\x36\x5E\x9B\x11\x23\xE3\x1C\xB2\xDF\xC7\x92\x9A\xE2\x96\x29\x71\x05\xE9\xC9\x2D\x30\x90\xC5\xA1\x1E\x03\xB4\x8C\x56\x75\x54\xB0\x08\xC3\xC7\x4C\xD4\xD0\x0E\x92\xFB\x53\x22\x9B\x91\xBB\x29\x5D\x1E\x76\xF7\xD8\xD9\xDF\x56\xF3\xB3\x87\x15\xBD\x1E\x7C\xEF\x2D\xDB\x33\x5A\x3D\xD4\xC2\x86\xE2\x40\x04\x09\xAA\x9C\x2E\x3B\xD9\x2F\x9D\xCF\xAF\x53\xEA\x34\x44\x14\x4B\xBB\x87\xFF\x09\x6E\xD2\xD7\xAE\xF0\x5F\xE9\xC5\x36\x8F\xB0\x18\x41\x06\x04\xD9\xAF\x38";

const char	testVectorAccumulated[] = 
	"\x58\x54\x97\x2E\x1A\x8F\x2B\x47\x11\x7A\xC5\x8B\x17\x84\xD0\x70\xC6\x55\xCE\x5F\x81\x9F\x5D\x76\x89\xD6\xD3\x9F\x09\x5B\x98\x0F\x85\x70\xFE\xC8\x12\x62\x4A\x28\x5C\xF4\x25\x47\x37\xA1\xFD\x70\x63\xD0\xCA\x74\x1F\x8F\x49\x22\xF8\xF2\x36\x76\x33\x8C\x7D\xBA\x07\x1F\xF9\xFD\x17\x00\xFE\x96\xEC\x0E\xD1\x97\x6C\x04\x62\x68\x9B\x1D\x2B\x18\x5F\x7B\xBF\x73\xEB\xC3\x7F\xD3\x2C\xEC\xFB\xE1\x30\x00\xC4\x2D\x70\x9F\x81\xC7\xE1\x1C\xA8\x07\x04\xEB\xCF\x91\x40\xE7\xBF\x03\xD7\x54\xA3\xA9\xFC\x5F\x6F\x27\x11\xD8\xA5\xBA";

#elif    (cKeccakB    == 1600) && (cKeccakR == 1088)

const char	testVectorSqueezed[] = 
	"\x34\x8F\xB7\x74\xAD\xC9\x70\xA1\x6B\x11\x05\x66\x94\x42\x62\x5E\x6A\xDA\xA8\x25\x7A\x89\xEF\xFD\xB5\xA8\x02\xF1\x61\xB8\x62\xEA\xD4\xB9\x38\xBE\x13\xC4\x0C\x95\x48\x44\x42\x75\xEE\x98\x9A\xF2\x38\x6D\x9C\x4C\x6B\x01\xDF\x21\xC9\x07\x5D\x20\x50\xB7\x36\x45\x19\x5C\x37\xB4\x27\x18\x79\x32\xC4\x28\x66\x0B\x6D\xFE\x00\x82\xE0\x74\x27\x76\x42\x4B\x0A\x1F\x9D\x9F\x3A\x16\x9E\x85\x76\x68\x96\x9D\xFB\x39\x82\xBC\x45\xB0\x4B\x39\x57\xA8\x7A\xDF\xF7\xAE\x2B\x8F\xC7\xD2\xB1\x53\x0B\xCD\x0D\x84\x05\xEF\x75\x93\x26\x33";

const char	testVectorAccumulated[] = 
	"\xDC\x8D\x2C\x9F\xC2\x42\x56\xF5\xBF\x51\xF0\xC5\x60\xF6\x74\x98\x8B\xF5\x36\x97\x5A\xE8\x62\x3E\xB1\x9E\x9A\x30\x16\x7B\x8F\x03\x56\xFF\x7E\x0C\xE0\xF4\xDD\x99\x92\xE2\xE1\x1F\xE8\x55\xED\xB9\x44\xE4\x01\x34\xEF\xCC\x41\xCF\x2E\x6C\xE1\x88\x13\xEA\xEE\xAF\xC1\x77\xB4\xE0\x76\xC1\x48\x54\x0B\x55\x9C\x76\x53\x44\x11\x59\xA1\x42\x72\xB8\x99\x6C\xE2\x0A\xAF\x41\x7B\x53\xB1\x80\x3C\xCA\x78\x33\x3E\x1C\x2E\x17\xCF\x75\xE8\x52\x82\xBD\xC5\xA8\x3C\xE5\xF5\xDA\xBE\x4B\xD6\x53\xE7\xD1\x47\xBF\x41\x92\x4F\x12\xD2\x22";

#elif    (cKeccakB    == 1600) && (cKeccakR == 832)

const char	testVectorSqueezed[] = 
	"\x6B\xFF\x1C\x84\x05\xA3\xFE\x59\x4E\x36\x0E\x3B\xCC\xEA\x1E\xBC\xD5\x09\x31\x0D\xC7\x9B\x9E\x45\xC2\x63\x78\x3D\x7A\x5D\xD6\x62\xC6\x78\x9B\x18\xBD\x56\x7D\xBD\xDA\x15\x54\xF5\xBE\xE6\xA8\x60\x16\x28\xC0\x22\xB7\x87\x92\x0C\xA0\x09\x63\x86\x2B\x42\x7A\x55\xDF\x89\x67\xF9\xE7\x6C\xD5\xA6\x3A\x70\xDA\xF4\xC5\x52\x36\x0B\x0D\x0F\x79\xF3\x8B\x4D\x12\x01\x1C\xD0\xC3\x1D\xAD\x23\x72\x9C\xE3\xB0\x87\x2E\xD6\xDC\x4B\x61\xF6\x9A\xD7\x26\x4F\x58\xA5\xFF\xE0\x8A\x88\x76\x56\x78\x3D\xA0\xC6\x91\xE1\x34\x89\xD6\x07\xFC";

const char	testVectorAccumulated[] = 
	"\x04\xB1\xDF\x77\xF8\xD1\x1B\x96\xE0\xFB\x79\x87\xD1\xF5\x7A\xAC\x05\x6F\x38\xEF\x70\x1A\x91\x68\xE1\xA2\x2B\x99\xEB\x9D\xBB\x8E\x05\x91\xFD\x82\x76\xD7\xBB\x40\x42\xFE\x79\xEE\x6F\xD0\x18\x7D\x87\xF2\xF7\x9A\x4F\x14\x3D\x1A\x13\xF3\xA2\x9C\x20\x92\xF2\x0E\x48\x6F\x9F\x27\x00\x3A\xD5\xFB\xFC\xEA\x5A\xCA\xE1\x1C\x5B\xBF\x06\xE6\xDD\x50\xFF\x2D\x96\xE5\x12\xE5\x8B\xE1\xDB\x32\x20\x7B\xA4\x27\x79\xEE\x02\x77\xFE\xBC\x75\x55\x6A\x04\xC1\xCE\xA8\x0B\xE6\xE8\x36\x89\x29\xF4\x13\x4C\x79\xD6\x06\xFC\xF0\x12\xC8\x0D";

#elif    (cKeccakB    == 1600) && (cKeccakR == 576)

const char	testVectorSqueezed[] = 
	"\x81\x95\x0E\x70\x96\xD3\x1D\x4F\x22\xE3\xDB\x71\xCA\xC7\x25\xBF\x59\xE8\x1A\xF5\x4C\x7C\xA9\xE6\xAE\xEE\x71\xC0\x10\xFC\x54\x67\x46\x63\x12\xA0\x1A\xA5\xC1\x37\xCF\xB1\x40\x64\x69\x41\x55\x67\x96\xF6\x12\xC9\x35\x12\x68\x73\x7C\x7E\x9A\x2B\x96\x31\xD1\xFA\x71\x83\x46\x26\x3A\x08\x73\x24\x43\x22\x67\x61\x86\x99\x14\xD4\x4B\x99\x40\xD0\x41\x05\x53\x6A\x35\xD4\x56\xFA\x65\xB4\x1D\x2E\x33\xC9\x85\x60\x18\x40\x05\x15\xDA\xB7\xB9\x68\xF6\x51\x00\xC8\x06\x46\x66\x61\x5A\xE6\x95\xBB\xB0\x88\x3A\xBD\xEB\x59\x33\xE6";

const char	testVectorAccumulated[] = 
	"\x56\x1E\x2E\x43\x33\xD2\xB1\xC5\x46\x6A\x8D\x49\x36\x9C\x02\xA2\x7E\x41\xC2\xAE\x84\xAD\x17\x02\x9E\x3B\xB7\xE2\x0B\x90\x7F\x27\x51\x9A\xBF\x76\x20\x73\x54\xDD\xAD\xC2\xC6\xEA\x45\x3E\xC9\x11\x67\xDA\xA3\x05\xF1\xAC\x52\x85\xCC\xD8\x7F\x72\x70\x38\x8E\x47\x95\x84\x5F\x06\xB5\x81\x2A\x5D\xF8\x2B\x55\x2E\xCC\x4E\x20\x89\x21\x2B\xF9\x01\x6D\xF0\xE9\x90\xC6\x0A\xD6\x0D\x18\xF1\x75\xC9\xDA\x53\xB2\x53\x41\xF8\xD6\x81\x70\xF0\x8C\xB9\xEC\x2E\x77\xA8\x2A\xEB\x4B\x9B\x20\x85\x29\xB9\xED\xD3\x7F\xED\xB8\x6A\x9B\x75";

#endif

#define    cKeccakMessageSizeInBytes	(sizeof(testVectorMessage) - 1)
#define    cKeccakHashSizeInBytes			(sizeof(testVectorSqueezed) - 1)

unsigned char input[(cKeccakMessageSizeInBytes > 512) ? cKeccakMessageSizeInBytes : 512];
unsigned char output[cKeccakHashSizeInBytes];
unsigned char ref[cKeccakHashSizeInBytes];

int main( void )
{
	{
        unsigned char i;

		//	One test vector for crypto_hash()
		for ( i = 0; i < cKeccakMessageSizeInBytes; i++ )
		{
			input[i] = (unsigned char)testVectorMessage[i];
		}

		crypto_hash( output, input, cKeccakMessageSizeInBytes );

		for ( i = 0; (i < cKeccakHashSizeInBytes) && (i < crypto_hash_BYTES); i++ )
		{
			if ( output[i] != (unsigned char)testVectorSqueezed[i] ) 
			{
				for ( ; ; );
			}
		}
	}

	{
		#define	refLen	cKeccakHashSizeInBytes
		unsigned int inlen, offset, size;
		int result;
		hashState			state;

		//	Acumulated test vector for crypto_hash()
		memset( ref, 0x00, sizeof(ref) );

		for ( inlen = 0; inlen <= (sizeof(input) * 8); (inlen < 2*8) ? inlen++ : ((inlen < 32*8) ? (inlen += 8) : (inlen <<= 1))  )
		{
			unsigned int i;
			unsigned int bytesize = (unsigned int)((inlen + 7) / 8);

			for ( i = 0; i < bytesize; ++i )
			{
				input[i] = (unsigned char)(i - bytesize);
			}

			result = Init( &state );
			if ( result != 0 )
			{
				for (;;);
			}

			for ( offset = 0; offset < inlen; offset += size )
			{
				//	vary sizes for Update()
				if ( (inlen %8) < 2 )
				{
					//	byte per byte
					size = 8;
				}
				else if ( (inlen %8) < 4 )
				{
					//	incremental
					size = offset + 8;
				}
				else
				{
					//	random
					size = ((rand() % ((inlen + 8) / 8)) + 1) * 8;
				}

				if ( size > (inlen - offset) ) 
				{
					size = inlen - offset;
				}
				result = Update( &state, input + offset / 8, size );
				if ( result != 0 )
				{
					for (;;);
				}
			}
			result = Final( &state, output, refLen );
			if ( result != 0 )
			{
				for (;;);
			}

			for ( i = 0; i < (unsigned int)refLen; ++i )
			{
				ref[i] ^= output[i];
			}
		}

        {
            unsigned char i;
            for ( i = 0; i < (unsigned char)refLen; i++ )
            {
                if ( ref[i] != (unsigned char)testVectorAccumulated[i] ) 
                {
				    for ( ; ; );
                }
            }
        }
	}

    //printf("OK!\n");
	return ( 0 );
}
