/*************************************************************************** * Copyright 2013 CertiVox UK Ltd. * * This file is part of CertiVox MIRACL Crypto SDK. * * The CertiVox MIRACL Crypto SDK provides developers with an * extensive and efficient set of cryptographic functions. * For further information about its features and functionalities please * refer to http://www.certivox.com * * * The CertiVox MIRACL Crypto SDK is free software: you can * redistribute it and/or modify it under the terms of the * GNU Affero General Public License as published by the * Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * * The CertiVox MIRACL Crypto SDK is distributed in the hope * that it will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * * * You should have received a copy of the GNU Affero General Public * License along with CertiVox MIRACL Crypto SDK. * If not, see . * * You can be released from the requirements of the license by purchasing * a commercial license. Buying such a license is mandatory as soon as you * develop commercial activities involving the CertiVox MIRACL Crypto SDK * without disclosing the source code of your own applications, or shipping * the CertiVox MIRACL Crypto SDK with a closed source product. * * ***************************************************************************/ /* * Implementation of the Secure Hashing Algorithm SHA3 - Keccak * M. Scott 19/06/2013 * * For use with byte-oriented messages only. * * NOTE: This requires a 64-bit integer type to be defined */ #include "miracl.h" #ifdef mr_unsign64 /* round constants */ static const mr_unsign64 RC[24]={ 0x0000000000000001LL,0x0000000000008082LL,0x800000000000808ALL,0x8000000080008000LL, 0x000000000000808BLL,0x0000000080000001LL,0x8000000080008081LL,0x8000000000008009LL, 0x000000000000008ALL,0x0000000000000088LL,0x0000000080008009LL,0x000000008000000ALL, 0x000000008000808BLL,0x800000000000008BLL,0x8000000000008089LL,0x8000000000008003LL, 0x8000000000008002LL,0x8000000000000080LL,0x000000000000800ALL,0x800000008000000ALL, 0x8000000080008081LL,0x8000000000008080LL,0x0000000080000001LL,0x8000000080008008LL}; /* functions */ #define SHA3_ROUNDS 24 #define rotl(x,n) (((x)<>(64-n))) /* permutation */ static void shs_transform(sha3 *sh) { int i,j,k; mr_unsign64 C[5],D[5],B[5][5]; for (k=0;kS[0][0]^sh->S[0][1]^sh->S[0][2]^sh->S[0][3]^sh->S[0][4]; C[1]=sh->S[1][0]^sh->S[1][1]^sh->S[1][2]^sh->S[1][3]^sh->S[1][4]; C[2]=sh->S[2][0]^sh->S[2][1]^sh->S[2][2]^sh->S[2][3]^sh->S[2][4]; C[3]=sh->S[3][0]^sh->S[3][1]^sh->S[3][2]^sh->S[3][3]^sh->S[3][4]; C[4]=sh->S[4][0]^sh->S[4][1]^sh->S[4][2]^sh->S[4][3]^sh->S[4][4]; D[0]=C[4]^rotl(C[1],1); D[1]=C[0]^rotl(C[2],1); D[2]=C[1]^rotl(C[3],1); D[3]=C[2]^rotl(C[4],1); D[4]=C[3]^rotl(C[0],1); for (i=0;i<5;i++) for (j=0;j<5;j++) sh->S[i][j]^=D[i]; /* let the compiler unroll it! */ B[0][0]=sh->S[0][0]; B[1][3]=rotl(sh->S[0][1],36); B[2][1]=rotl(sh->S[0][2],3); B[3][4]=rotl(sh->S[0][3],41); B[4][2]=rotl(sh->S[0][4],18); B[0][2]=rotl(sh->S[1][0],1); B[1][0]=rotl(sh->S[1][1],44); B[2][3]=rotl(sh->S[1][2],10); B[3][1]=rotl(sh->S[1][3],45); B[4][4]=rotl(sh->S[1][4],2); B[0][4]=rotl(sh->S[2][0],62); B[1][2]=rotl(sh->S[2][1],6); B[2][0]=rotl(sh->S[2][2],43); B[3][3]=rotl(sh->S[2][3],15); B[4][1]=rotl(sh->S[2][4],61); B[0][1]=rotl(sh->S[3][0],28); B[1][4]=rotl(sh->S[3][1],55); B[2][2]=rotl(sh->S[3][2],25); B[3][0]=rotl(sh->S[3][3],21); B[4][3]=rotl(sh->S[3][4],56); B[0][3]=rotl(sh->S[4][0],27); B[1][1]=rotl(sh->S[4][1],20); B[2][4]=rotl(sh->S[4][2],39); B[3][2]=rotl(sh->S[4][3],8); B[4][0]=rotl(sh->S[4][4],14); for (i=0;i<5;i++) for (j=0;j<5;j++) sh->S[i][j]=B[i][j]^(~B[(i+1)%5][j]&B[(i+2)%5][j]); sh->S[0][0]^=RC[k]; } } /* Re-Initialize. olen is output length in bytes - should be 28, 32, 48 or 64 (224, 256, 384, 512 bits resp.) */ void sha3_init(sha3 *sh,int olen) { int i,j; for (i=0;i<5;i++) for (j=0;j<5;j++) sh->S[i][j]=0; /* 5x5x8 bytes = 200 bytes of state */ sh->length=0; sh->len=olen; sh->rate=200-2*olen; /* number of bytes consumed in one gulp. Note that some bytes in the state ("capacity") are not touched. Gulps are smaller for larger digests. Important that olenlength%sh->rate); int i,j,b=cnt%8; cnt/=8; i=cnt%5; j=cnt/5; /* process by columns! */ sh->S[i][j]^=((mr_unsign64)byte<<(8*b)); sh->length++; if (sh->length%sh->rate==0) shs_transform(sh); } void sha3_hash(sha3 *sh,char *hash) { /* pad message and finish - supply digest */ int i,j,k,m=0; mr_unsign64 el; int q=sh->rate-(sh->length%sh->rate); if (q==1) sha3_process(sh,0x86); else { sha3_process(sh,0x06); while (sh->length%sh->rate!=sh->rate-1) sha3_process(sh,0x00); sha3_process(sh,0x80); /* this will force a final transform */ } /* extract by columns - assuming here digest size < rate */ for (j=0;j<5;j++) for (i=0;i<5;i++) { el=sh->S[i][j]; for (k=0;k<8;k++) { hash[m++]=(el&0xff); if (m>=sh->len) return; el>>=8; } } } #endif /* test program - see http://www.di-mgt.com.au/sha_testvectors.html //char *s="abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; //char *s="abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; char *s="abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno"; int main() { mr_unsign64 ii; int i,j,k,olen; char hash[64]; sha3 sh; for (j=0;j<4;j++) { if (j==0) olen=28; if (j==1) olen=32; if (j==2) olen=48; if (j==3) olen=64; sha3_init(&sh,olen); // for (ii=0;ii<16777216;ii++) // { // for (k=0;k