/* Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, Joan Daemen, Michaƫl Peeters, Gilles Van Assche and Ronny Van Keer, hereby denoted as "the implementer". For more information, feedback or questions, please refer to our websites: http://keccak.noekeon.org/ http://keyak.noekeon.org/ http://ketje.noekeon.org/ 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 #include #include #include #include /* =============================================================================================== */ /* align.h */ #ifdef ALIGN #undef ALIGN #endif #if defined(__GNUC__) #define ALIGN(x) __attribute__ ((aligned(x))) #elif defined(_MSC_VER) #define ALIGN(x) __declspec(align(x)) #elif defined(__ARMCC_VERSION) #define ALIGN(x) __align(x) #else #define ALIGN(x) #endif /* =============================================================================================== */ /* KeccakSponge.h */ #define KCP_DeclareSpongeStructure(prefix, size, alignment) \ ALIGN(alignment) typedef struct prefix##_SpongeInstanceStruct { \ unsigned char state[size]; \ unsigned int rate; \ unsigned int byteIOIndex; \ int squeezing; \ } prefix##_SpongeInstance; #define KCP_DeclareSpongeFunctions(prefix) \ int prefix##_Sponge(unsigned int rate, unsigned int capacity, const unsigned char *input, size_t inputByteLen, unsigned char suffix, unsigned char *output, size_t outputByteLen); \ int prefix##_SpongeInitialize(prefix##_SpongeInstance *spongeInstance, unsigned int rate, unsigned int capacity); \ int prefix##_SpongeAbsorb(prefix##_SpongeInstance *spongeInstance, const unsigned char *data, size_t dataByteLen); \ int prefix##_SpongeAbsorbLastFewBits(prefix##_SpongeInstance *spongeInstance, unsigned char delimitedData); \ int prefix##_SpongeSqueeze(prefix##_SpongeInstance *spongeInstance, unsigned char *data, size_t dataByteLen); /* =============================================================================================== */ /* KeccakP-200-SnP.h */ #define KeccakP200_implementation "8-bit compact implementation" #define KeccakP200_stateSizeInBytes 25 #define KeccakP200_stateAlignment 1 #define KeccakP200_StaticInitialize() void KeccakP200_Initialize(void *state); void KeccakP200_AddByte(void *state, unsigned char data, unsigned int offset); void KeccakP200_AddBytes(void *state, const unsigned char *data, unsigned int offset, unsigned int length); void KeccakP200_OverwriteBytes(void *state, const unsigned char *data, unsigned int offset, unsigned int length); void KeccakP200_OverwriteWithZeroes(void *state, unsigned int byteCount); void KeccakP200_Permute_Nrounds(void *state, unsigned int nrounds); void KeccakP200_Permute_18rounds(void *state); void KeccakP200_ExtractBytes(const void *state, unsigned char *data, unsigned int offset, unsigned int length); void KeccakP200_ExtractAndAddBytes(const void *state, const unsigned char *input, unsigned char *output, unsigned int offset, unsigned int length); /* =============================================================================================== */ /* More of KeccakSponge.h */ KCP_DeclareSpongeStructure(KeccakWidth200, KeccakP200_stateSizeInBytes, KeccakP200_stateAlignment) KCP_DeclareSpongeFunctions(KeccakWidth200) /* =============================================================================================== */ /* KeccakP-200-compact.c */ #define UNROLL_CHILOOP //comment if more compact using for loop typedef unsigned char UINT8; typedef unsigned int tSmallUInt; /*INFO It could be more optimized to use "unsigned char" on an 8-bit CPU */ typedef UINT8 tKeccakLane; #define ROL8(a, offset) (UINT8)((((UINT8)a) << (offset&7)) ^ (((UINT8)a) >> (8-(offset&7)))) const UINT8 KeccakP200_RotationConstants[25] = { 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 }; const UINT8 KeccakP200_PiLane[25] = { 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 }; #if defined(DIVISION_INSTRUCTION) #define MOD5(argValue) ((argValue) % 5) #else const UINT8 KeccakP200_Mod5[10] = { 0, 1, 2, 3, 4, 0, 1, 2, 3, 4 }; #define MOD5(argValue) KeccakP200_Mod5[argValue] #endif const UINT8 KeccakF200_RoundConstants[] = { 0x01, 0x82, 0x8a, 0x00, 0x8b, 0x01, 0x81, 0x09, 0x8a, 0x88, 0x09, 0x0a, 0x8b, 0x8b, 0x89, 0x03, 0x02, 0x80 }; /* ---------------------------------------------------------------- */ void KeccakP200_Initialize(void *argState) { memset( argState, 0, 25 * sizeof(tKeccakLane) ); } /* ---------------------------------------------------------------- */ void KeccakP200_AddByte(void *argState, unsigned char byte, unsigned int offset) { ((tKeccakLane*)argState)[offset] ^= byte; } /* ---------------------------------------------------------------- */ void KeccakP200_AddBytes(void *argState, const unsigned char *data, unsigned int offset, unsigned int length) { tSmallUInt i; //printf("INSIDE AddBytes : Offset %u and Length %u!\n", offset, length); fflush(stdout); tKeccakLane * state = (tKeccakLane*)argState + offset; for(i=0; i SnP_width) || ((rate % 8) != 0)) return 1; if (suffix == 0) return 1; // Initialize the state SnP_StaticInitialize(); SnP_Initialize(state); // First, absorb whole blocks #ifdef SnP_FastLoop_Absorb if (((rateInBytes % (SnP_width/200)) == 0) && (inputByteLen >= rateInBytes)) { // fast lane: whole lane rate j = SnP_FastLoop_Absorb(state, rateInBytes/(SnP_width/200), curInput, inputByteLen); curInput += j; inputByteLen -= j; } #endif while(inputByteLen >= (size_t)rateInBytes) { SnP_AddBytes(state, curInput, 0, rateInBytes); SnP_Permute(state); curInput += rateInBytes; inputByteLen -= rateInBytes; } // Then, absorb what remains partialBlock = (unsigned int)inputByteLen; SnP_AddBytes(state, curInput, 0, partialBlock); // Finally, absorb the suffix // Last few bits, whose delimiter coincides with first bit of padding SnP_AddByte(state, suffix, partialBlock); // If the first bit of padding is at position rate-1, we need a whole new block for the second bit of padding if ((suffix >= 0x80) && (partialBlock == (rateInBytes-1))) SnP_Permute(state); // Second bit of padding SnP_AddByte(state, 0x80, rateInBytes-1); SnP_Permute(state); // First, output whole blocks while(outputByteLen > (size_t)rateInBytes) { SnP_ExtractBytes(state, curOutput, 0, rateInBytes); SnP_Permute(state); curOutput += rateInBytes; outputByteLen -= rateInBytes; } // Finally, output what remains partialBlock = (unsigned int)outputByteLen; SnP_ExtractBytes(state, curOutput, 0, partialBlock); return 0; } /* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */ int SpongeInitialize(SpongeInstance *instance, unsigned int rate, unsigned int capacity) { if (rate+capacity != SnP_width) return 1; if ((rate <= 0) || (rate > SnP_width) || ((rate % 8) != 0)) return 1; //printf("SpongeInitialize called: rate %u\tcapacity %u!\n", rate, capacity); fflush(stdout); SnP_StaticInitialize(); SnP_Initialize(instance->state); instance->rate = rate; instance->byteIOIndex = 0; instance->squeezing = 0; //printf("SpongeInitialize called: rate %u!\n", instance->rate); fflush(stdout); return 0; } /* ---------------------------------------------------------------- */ int SpongeAbsorb(SpongeInstance *instance, const unsigned char *data, size_t dataByteLen) { size_t i, j; unsigned int partialBlock; const unsigned char *curData; unsigned int rateInBytes = instance->rate/8; //printf("Entering SpongeAbsort: rateInBytes %d!\n", rateInBytes); fflush(stdout); if (instance->squeezing) return 1; // Too late for additional input i = 0; curData = data; while(i < dataByteLen) { if ((instance->byteIOIndex == 0) && (dataByteLen >= (i + rateInBytes))) { #ifdef SnP_FastLoop_Absorb // processing full blocks first if ((rateInBytes % (SnP_width/200)) == 0) { // fast lane: whole lane rate j = SnP_FastLoop_Absorb(instance->state, rateInBytes/(SnP_width/200), curData, dataByteLen - i); i += j; curData += j; } else { #endif for( j = dataByteLen-i; j >= rateInBytes; j -= rateInBytes) { // DEBUG //printf("IF COMPONENT: Before AddBytes!\n"); fflush(stdout); //int z; //printf("TO BE ABSORBED\t"); //for ( z = 0; z < rateInBytes; z++ ) // printf("%02X\t", (unsigned char)curData[z]); //printf("\n"); fflush(stdout); SnP_AddBytes(instance->state, curData, 0, rateInBytes); SnP_Permute(instance->state); curData+=rateInBytes; } i = dataByteLen - j; #ifdef SnP_FastLoop_Absorb } #endif } else { // normal lane: using the message queue partialBlock = (unsigned int)(dataByteLen - i); if (partialBlock+instance->byteIOIndex > rateInBytes) partialBlock = rateInBytes - instance->byteIOIndex; // DEBUG //printf("ELSE COMPONENT: Before AddBytes!\n"); fflush(stdout); //int z; //printf("TO BE ABSORBED\t"); //for ( z = 0; z < rateInBytes; z++ ) // printf("%02X\t", (unsigned char)curData[z]); //printf("\n"); fflush(stdout); i += partialBlock; SnP_AddBytes(instance->state, curData, instance->byteIOIndex, partialBlock); curData += partialBlock; instance->byteIOIndex += partialBlock; if (instance->byteIOIndex == rateInBytes) { SnP_Permute(instance->state); instance->byteIOIndex = 0; } } } return 0; } /* ---------------------------------------------------------------- */ int SpongeAbsorbLastFewBits(SpongeInstance *instance, unsigned char delimitedData) { unsigned int rateInBytes = instance->rate/8; if (delimitedData == 0) return 1; if (instance->squeezing) return 1; // Too late for additional input //printf("SpongeAbsorbLastFewBits: XORing %02x at index %d!\n", delimitedData, instance->byteIOIndex); fflush(stdout); // Last few bits, whose delimiter coincides with first bit of padding SnP_AddByte(instance->state, delimitedData, instance->byteIOIndex); // If the first bit of padding is at position rate-1, we need a whole new block for the second bit of padding if ((delimitedData >= 0x80) && (instance->byteIOIndex == (rateInBytes-1))) SnP_Permute(instance->state); //printf("SpongeAbsorbLastFewBits: XORing %02x at index %d!\n", 0x80, rateInBytes-1); fflush(stdout); // Second bit of padding SnP_AddByte(instance->state, 0x80, rateInBytes-1); SnP_Permute(instance->state); instance->byteIOIndex = 0; instance->squeezing = 1; return 0; } /* ---------------------------------------------------------------- */ int SpongeSqueeze(SpongeInstance *instance, unsigned char *data, size_t dataByteLen) { size_t i, j; unsigned int partialBlock; unsigned int rateInBytes = instance->rate/8; unsigned char *curData; //printf("SpongeSqueeze called!\n"); fflush(stdout); if (!instance->squeezing) { //printf("SpongeSqueeze: Calling SpongeAbsortLastFewBits!\n"); fflush(stdout); SpongeAbsorbLastFewBits(instance, 0x01); } i = 0; curData = data; while(i < dataByteLen) { if ((instance->byteIOIndex == rateInBytes) && (dataByteLen >= (i + rateInBytes))) { for(j=dataByteLen-i; j>=rateInBytes; j-=rateInBytes) { SnP_Permute(instance->state); SnP_ExtractBytes(instance->state, curData, 0, rateInBytes); curData+=rateInBytes; } i = dataByteLen - j; } else { // normal lane: using the message queue if (instance->byteIOIndex == rateInBytes) { SnP_Permute(instance->state); instance->byteIOIndex = 0; } partialBlock = (unsigned int)(dataByteLen - i); if (partialBlock+instance->byteIOIndex > rateInBytes) partialBlock = rateInBytes-instance->byteIOIndex; i += partialBlock; SnP_ExtractBytes(instance->state, curData, instance->byteIOIndex, partialBlock); curData += partialBlock; instance->byteIOIndex += partialBlock; } } return 0; } /* ---------------------------------------------------------------- */ #undef Sponge #undef SpongeInstance #undef SpongeInitialize #undef SpongeAbsorb #undef SpongeAbsorbLastFewBits #undef SpongeSqueeze #undef SnP_stateSizeInBytes #undef SnP_stateAlignment #undef SnP_StaticInitialize #undef SnP_Initialize #undef SnP_AddByte #undef SnP_AddBytes #undef SnP_ExtractBytes /* =============================================================================================== */ /* MORE OF KeccakSponge.c */ #undef prefix #undef SnP #undef SnP_width #undef SnP_Permute #undef SnP_FastLoop_Absorb /* =============================================================================================== */ /* KeccakHash.h */ typedef unsigned char BitSequence; typedef size_t DataLength; typedef enum { SUCCESS = 0, FAIL = 1, BAD_HASHLEN = 2 } HashReturn; typedef struct { KeccakWidth200_SpongeInstance sponge; unsigned int fixedOutputLength; unsigned char delimitedSuffix; } Keccak_HashInstance; /* =============================================================================================== */ /* KeccakHash.c */ /* ---------------------------------------------------------------- */ HashReturn Keccak_HashInitialize(Keccak_HashInstance *instance, unsigned int rate, unsigned int capacity, unsigned int hashbitlen, unsigned char delimitedSuffix) { HashReturn result; if ( delimitedSuffix == 0 ) return FAIL; result = (HashReturn)KeccakWidth200_SpongeInitialize(&instance->sponge, rate, capacity); if (result != SUCCESS) return result; instance->fixedOutputLength = hashbitlen; instance->delimitedSuffix = delimitedSuffix; return SUCCESS; } /* ---------------------------------------------------------------- */ HashReturn Keccak_HashUpdate(Keccak_HashInstance *instance, const BitSequence *data, DataLength databitlen) { //printf("Keccak_HashUpdate called!\n"); fflush(stdout); if ((databitlen % 8) == 0) return (HashReturn)KeccakWidth200_SpongeAbsorb(&instance->sponge, data, databitlen/8); else { HashReturn ret = (HashReturn)KeccakWidth200_SpongeAbsorb(&instance->sponge, data, databitlen/8); if (ret == SUCCESS) { // The last partial byte is assumed to be aligned on the least significant bits unsigned char lastByte = data[databitlen/8]; // Concatenate the last few bits provided here with those of the suffix unsigned short delimitedLastBytes = (unsigned short)((unsigned short)lastByte | ((unsigned short)instance->delimitedSuffix << (databitlen % 8))); if ((delimitedLastBytes & 0xFF00) == 0x0000) { instance->delimitedSuffix = delimitedLastBytes & 0xFF; } else { unsigned char oneByte[1]; oneByte[0] = delimitedLastBytes & 0xFF; ret = (HashReturn)KeccakWidth200_SpongeAbsorb(&instance->sponge, oneByte, 1); instance->delimitedSuffix = (delimitedLastBytes >> 8) & 0xFF; } } return ret; } } /* ---------------------------------------------------------------- */ HashReturn Keccak_HashFinal(Keccak_HashInstance *instance, BitSequence *hashval) { HashReturn ret; //printf("Keccak_HashFinal called!\n"); fflush(stdout); ret = (HashReturn)KeccakWidth200_SpongeAbsorbLastFewBits(&instance->sponge, instance->delimitedSuffix); if (ret == SUCCESS) return (HashReturn)KeccakWidth200_SpongeSqueeze(&instance->sponge, hashval, instance->fixedOutputLength/8); else return ret; } /* ---------------------------------------------------------------- */ HashReturn Keccak_HashSqueeze(Keccak_HashInstance *instance, BitSequence *data, DataLength databitlen) { if ((databitlen % 8) != 0) return FAIL; return (HashReturn)KeccakWidth200_SpongeSqueeze(&instance->sponge, data, databitlen/8); } /* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */ int ComputeHashKeccak(int hash_in_len_bytes, unsigned char hash_in_bin_str[hash_in_len_bytes], int hash_out_len_bytes, unsigned char hash_out[hash_out_len_bytes]) { Keccak_HashInstance instance; int j; // DEBUG //printf("\tHash in:\t"); //for ( j = 0; j < hash_in_len_bytes; j++ ) // { printf("%02X\t", (unsigned char)(*(hash_in_bin_str + j))); } //printf("\n"); // If NO bits are to be absorbed on the right, then use i = 1 if ( Keccak_HashInitialize(&instance, 72, 128, 64, 0x01) == FAIL ) { printf("ERROR: ComputeHashKeccak(): Initialize failed!\n"); fflush(stdout); return(-1); } // Second param is defined as 'typedef unsigned char BitSequence'. NOTE: Bit 70 and 71 MUST // be ZERO otherwise Keccak runs TWO hashes. It will insert "11" in the upper two bits. if ( Keccak_HashUpdate(&instance, hash_in_bin_str, 70) == FAIL ) { printf("ERROR: ComputeHashKeccak(): Update failed!\n"); fflush(stdout); return(-1); } if ( Keccak_HashFinal(&instance, hash_out) == FAIL ) { printf("ERROR: ComputeHashKeccak(): Final failed!\n"); fflush(stdout); return(-1); } // DEBUG //printf("\tFinal out\t"); //for ( j = 0; j < 8; j++ ) // printf("%02X\t", (unsigned char)hash_out[j]); //printf("\n"); return 0; }