/*
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-avr8.h"
#include <avr/pgmspace.h>

#define cKeccakR_SizeInBytes    (cKeccakR / 8)
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#ifndef crypto_hash_BYTES
    #ifdef cKeccakFixedOutputLengthInBytes
        #define crypto_hash_BYTES cKeccakFixedOutputLengthInBytes
    #else
        #define crypto_hash_BYTES cKeccakR_SizeInBytes
    #endif
#endif

#if		(cKeccakR == 1152)

//All-in-one test for Keccak[r=1152, c=448]
const unsigned char testVectorAccumulated[128] PROGMEM = 
"\x02\x57\x78\x6E\xA6\xA0\x75\xC2\xD1\x16\x7E\x19\x8B\xD6\x60\x3D\xC9\x2D\x31\xD9\xF2\x24\x94\x3E\x10\xBE\x2D\x77\x2F\xFC\xB6\xCE\xAE\x69\xB0\x30\xA0\xC2\xE2\x40\xB4\xAA\x7E\x42\x64\x8D\x88\x1E\x98\x0B\xC5\x2D\x9B\x64\x9B\x03\x10\x08\xF8\x0C\x71\x11\x69\x2B\xB9\x2A\xB8\x6E\x14\x93\xAC\xFE\xEB\xF8\x73\x9B\x59\x65\x47\xE5\xDC\xE0\x29\x21\xD7\xF4\x84\x93\xC9\xBD\xB8\x97\x98\xD5\x69\x15\x38\x1A\x8F\x86\xB2\xAD\xC7\xD2\x63\x43\x69\xDD\x9E\x8A\x27\x58\xEE\xF9\x7B\xA1\x6D\xCC\xFE\x98\x2A\x64\xC5\x1D\x83\xDF\x68\x55";

#elif	(cKeccakR == 1088)

//All-in-one test for Keccak[r=1088, c=512]
const unsigned char testVectorAccumulated[128] PROGMEM = 
"\xD2\x53\x12\x20\x01\x89\x0C\x19\xCE\x06\x9D\x1A\xBE\x36\x7E\xBA\x43\x80\x14\xA1\xCA\xA4\xB3\x99\xAD\xBB\x9B\x1A\xD3\xDE\xA8\xE6\xE3\x44\xDC\xBA\x44\xB1\x5C\x52\x47\x32\xE0\x0F\xDF\x55\x15\x7B\xD3\x49\x0B\xD2\x58\x7D\xC0\x1E\x93\x1E\x8F\xFF\x28\xDC\x7F\x00\xE6\xDF\xD3\xBB\xDC\x94\x05\x5A\xA1\x5B\xB3\x29\x86\x25\x26\x3D\xC6\xB1\xEF\x3B\x89\x18\x20\x71\x92\xFA\xA7\x58\xA4\x8A\xF9\xFF\x19\x61\x96\xC4\x73\x91\x85\xF3\x19\x73\xE3\x52\x6D\xBD\x0A\xD9\xF8\x95\x68\x43\x31\x50\x90\xD7\x68\x5F\x75\xA1\x61\x1E\x08\x2D";

#elif	(cKeccakR == 1024)

//All-in-one test for Keccak[r=1024, c=576]
const unsigned char testVectorAccumulated[128] PROGMEM = 
"\x74\x00\x1E\xA7\xD2\xBE\x68\x0D\x36\x0C\x80\x0D\x6D\xDB\x4D\x07\x01\x10\xE5\x19\x99\x8C\x0C\x1C\x63\xCD\x5C\xC0\x2D\xC3\x12\x4C\x9C\xD1\xC1\x5A\x8E\xC9\x06\xA8\x1E\xE6\x02\x77\x14\x40\x38\xD5\x09\x89\xE2\x2D\xF2\x66\x37\x4A\x48\xBC\xB9\xE2\x7D\x53\x86\xAC\x1F\x3D\x4C\xEF\x4E\x90\x97\xFB\x9C\x45\x40\xED\xAB\x16\x29\x05\x87\x17\x26\xE8\xBD\xFA\x82\x72\x5F\x77\xFF\xFA\x26\xE6\x50\x0B\x1D\x40\x25\x62\xC7\xEE\xCA\xAA\x38\x78\x52\xE6\x15\x7B\xC7\x3E\x16\xB2\xFE\x05\xB8\x8D\x68\x0C\x18\xC1\x48\x0B\x50\x97\xD9\xC7";

const char	testVectorMessage[] PROGMEM = 
	"\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";

const char	testVectorSqueezed[] PROGMEM = 
	"\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";

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

#elif	(cKeccakR == 832)

//All-in-one test for Keccak[r=832, c=768]
const unsigned char testVectorAccumulated[128] PROGMEM = 
"\x6C\x07\xDB\x71\x61\x77\xCC\x99\xFF\xB4\x79\xA1\x54\xDC\xA7\xDA\x42\x6D\x5C\x04\x26\xBF\x01\xA2\x93\x9A\x35\xB1\xCC\x2E\x6C\x5D\xBA\x5E\x43\xAD\xD1\x7C\xA8\x45\xF5\x49\xA7\x02\xA3\x84\x4B\x7A\x15\x2B\x23\x9E\x41\xA7\x4C\x83\x09\x04\xF1\xBB\x40\x17\x7A\x67\x72\x3C\xF4\x28\x4B\xAB\x94\xC2\x02\xF4\x7B\x28\xB4\x5D\x57\xCA\x7E\x3F\x27\x0D\x2C\x09\x4F\x68\x54\xA3\xE6\x38\xF3\x82\x25\x0B\xC3\x16\x52\x2B\x8A\xDE\x93\x4F\x10\xC5\x21\x57\x4B\x21\xE7\xC6\xF6\xBB\x84\xF1\x7A\x78\x8E\xD3\x9E\xE2\xC7\x2F\xE3\x0F\xBB\x60";

#elif	(cKeccakR == 576)

//All-in-one test for Keccak[r=576, c=1024]
const unsigned char testVectorAccumulated[128] PROGMEM = 
"\xFB\x00\xFB\x55\x4B\xDA\x9D\x59\xD7\xD4\x42\x9A\xAB\xA5\x19\xA4\x14\x8D\x48\x67\xF6\xF0\xC8\x54\x1A\x48\xA4\x33\x4E\x68\xB7\xF0\x59\x13\x07\xED\xE3\x93\xE1\xA3\xA4\x79\x9E\x94\xDE\x9C\x32\x8A\xBB\x4F\xF2\x75\x47\xB0\x5E\x41\x7D\x78\xF6\x22\x0D\x83\x22\xC6\xB0\x7D\xBD\x2F\xB8\x5F\x4D\x99\x50\x86\xA5\x9B\x03\x51\x56\x35\x94\xB6\xFE\x72\x2B\x63\x7B\x4A\xDC\xDD\xA1\x83\xCF\xB7\xE7\xB2\x9D\x3A\x0D\x29\xBD\x30\xD4\xC5\x9F\x30\xBB\x60\x5A\x52\xC3\x83\x4B\xCA\xF4\x7D\x67\x37\x99\xBA\x28\x2E\xBC\x37\x76\xB3\x53\x56";

#endif

#define	MIN(a,b)	(((a) < (b)) ? (a) : (b))

#define	MAX_INPUT_LEN	(4096/8)

unsigned char input[MAX_INPUT_LEN];
unsigned char output[cKeccakR/8];
unsigned char accu[MIN(cKeccakR/8, 128)];

int main( void )
{
	unsigned int i;
	unsigned int size;

	#if	(cKeccakR == 1024)

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

		crypto_hash( output, input, cKeccakMessageSizeInBytes );

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

	//	small performance measurement
	crypto_hash( output, input, cKeccakR_SizeInBytes-1 );
	crypto_hash( output, input, 2*cKeccakR_SizeInBytes-1 );

	#endif

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

	for ( size = 0; size <= MAX_INPUT_LEN; ++size )
	{

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

		crypto_hash( output, input, size );

		for ( i = 0; i < MIN(crypto_hash_BYTES, 128); ++i )
		{
			accu[i] ^= output[i];
		}
	}
	for ( i = 0; i < MIN(crypto_hash_BYTES, 128); ++i )
	{
		if ( accu[i] != (unsigned char)pgm_read_byte(&testVectorAccumulated[i]) ) 
		{
			for ( ; ; );
		}
	}

	return ( 0 );
}
