/* This program gives the reference implementation of JH.
   It implements the standard description of JH (not bitslice)
   The description given in this program is suitable for hardware implementation

   --------------------------------
   Comparing to the original reference implementation,
   two functions are added to make the porgram more readable.
   One function is E8_initialgroup() at the beginning of E8;
   another function is E8_finaldegroup() at the end of E8.

   --------------------------------

   Last Modified: January 16, 2011
*/



#include 

typedef unsigned char BitSequence;
typedef unsigned long long DataLength;
typedef enum { SUCCESS = 0, FAIL = 1, BAD_HASHLEN = 2 } HashReturn;

typedef struct {
      int hashbitlen;                     /*the message digest size*/
      unsigned long long databitlen;      /*the message size in bits*/
      unsigned long long datasize_in_buffer;  /*the size of the message remained in buffer; assumed to be multiple of 8bits except for the last partial block at the end of the message*/
      unsigned char H[128];               /*the hash value H; 128 bytes;*/
      unsigned char A[256];               /*the temporary round value; 256 4-bit elements*/
      unsigned char roundconstant[64];    /*round constant for one round; 64 4-bit elements*/
      unsigned char buffer[64];           /*the message block to be hashed; 64 bytes*/
} hashState;

/*The constant for the Round 0 of E8*/
const unsigned char roundconstant_zero[64] = {0x6,0xa,0x0,0x9,0xe,0x6,0x6,0x7,0xf,0x3,0xb,0xc,0xc,0x9,0x0,0x8,0xb,0x2,0xf,0xb,0x1,0x3,0x6,0x6,0xe,0xa,0x9,0x5,0x7,0xd,0x3,0xe,0x3,0xa,0xd,0xe,0xc,0x1,0x7,0x5,0x1,0x2,0x7,0x7,0x5,0x0,0x9,0x9,0xd,0xa,0x2,0xf,0x5,0x9,0x0,0xb,0x0,0x6,0x6,0x7,0x3,0x2,0x2,0xa};

/*The two Sboxes S0 and S1*/
unsigned char S[2][16] = {{9,0,4,11,13,12,3,15,1,10,2,6,7,5,8,14},{3,12,6,13,5,7,1,9,15,2,0,4,11,10,14,8}};

/*The linear transformation L, the MDS code*/
#define L(a, b) {                                                       \
      (b) ^= ( ( (a) << 1) ^ ( (a) >> 3) ^ (( (a) >> 2) & 2) ) & 0xf;   \
      (a) ^= ( ( (b) << 1) ^ ( (b) >> 3) ^ (( (b) >> 2) & 2) ) & 0xf;   \
}

void R8(hashState *state);                    /* The round function of E8 */
void update_roundconstant(hashState *state);  /* Update the round constant of E8 */
void E8_initialgroup(hashState *state);       /* Grouping the state into 4-bit elements at the beginning of E8 */
void E8_finaldegroup(hashState *state);       /* Inverse of the grouping at the end of E8 */
void E8(hashState *state);                    /* The bijective function E8 */
void F8(hashState *state);                    /* The compression function F8 */

/*The API functions*/
HashReturn Init(hashState *state, int hashbitlen);
HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen);
HashReturn Final(hashState *state, BitSequence *hashval);
HashReturn Hash(int hashbitlen, const BitSequence *data,DataLength databitlen, BitSequence *hashval);

/*the round function of E8 */
void R8(hashState *state)
{
      unsigned int i;
      unsigned char tem[256],t;
      unsigned char roundconstant_expanded[256];  /*the round constant expanded into 256 1-bit element;*/

      /*expand the round constant into 256 one-bit element*/
      for (i = 0; i < 256; i++)  {
            roundconstant_expanded[i] = (state->roundconstant[i >> 2] >> (3 - (i & 3)) ) & 1;
      }

      /*S box layer, each constant bit selects one Sbox from S0 and S1*/
      for (i = 0; i < 256; i++) {
            tem[i] = S[roundconstant_expanded[i]][state->A[i]]; /*constant bits are used to determine which Sbox to use*/
      }

      /*MDS Layer*/
      for (i = 0; i < 256; i=i+2) L(tem[i], tem[i+1]);

      /*The following is the permuation layer P_8$

      /*initial swap Pi_8*/
      for ( i = 0; i < 256; i=i+4) {
            t = tem[i+2];
            tem[i+2] = tem[i+3];
            tem[i+3] = t;
      }

      /*permutation P'_8*/
      for (i = 0; i < 128; i=i+1) {
            state->A[i] = tem[i<<1];
            state->A[i+128] = tem[(i<<1)+1];
      }

      /*final swap Phi_8*/
      for ( i = 128; i < 256; i=i+2) {
            t = state->A[i];
            state->A[i] = state->A[i+1];
            state->A[i+1] = t;
      }
}


/*The following function generates the next round constant from the current
  round constant;  R6 is used for generating round constants for E8, with
  the round constants of R6 being set as 0;
*/
void update_roundconstant(hashState *state) {
      int i;
      unsigned char tem[64],t;

      /*Sbox layer*/
      for (i = 0; i < 64; i++)   tem[i] = S[0][state->roundconstant[i]];

      /*MDS layer*/
      for (i = 0; i < 64; i=i+2) L(tem[i], tem[i+1]);

      /*The following is the permutation layer P_6 */

      /*initial swap Pi_6*/
      for ( i = 0; i < 64; i=i+4) {
            t = tem[i+2];
            tem[i+2] = tem[i+3];
            tem[i+3] = t;
      }

      /*permutation P'_6*/
      for ( i = 0; i < 32; i=i+1) {
            state->roundconstant[i]    = tem[i<<1];
            state->roundconstant[i+32] = tem[(i<<1)+1];
      }

      /*final swap Phi_6*/
      for ( i = 32; i < 64; i=i+2 ) {
            t = state->roundconstant[i];
            state->roundconstant[i] = state->roundconstant[i+1];
            state->roundconstant[i+1] = t;
      }
}

/*initial group at the begining of E_8: group the bits of H into 4-bit elements of A.
  After the grouping, the i-th, (i+256)-th, (i+512)-th, (i+768)-th bits of state->H
  become the i-th 4-bit element of state->A
*/
void E8_initialgroup(hashState *state) {
      unsigned int i;
      unsigned char t0,t1,t2,t3;
      unsigned char tem[256];

      /*t0 is the i-th bit of H, i = 0, 1, 2, 3, ... , 127*/
      /*t1 is the (i+256)-th bit of H*/
      /*t2 is the (i+512)-th bit of H*/
      /*t3 is the (i+768)-th bit of H*/
      for (i = 0; i < 256; i++) {
            t0 = (state->H[i>>3] >> (7 - (i & 7)) ) & 1;
            t1 = (state->H[(i+256)>>3] >> (7 - (i & 7)) ) & 1;
            t2 = (state->H[(i+ 512 )>>3] >> (7 - (i & 7)) ) & 1;
            t3 = (state->H[(i+ 768 )>>3] >> (7 - (i & 7)) ) & 1;
            tem[i] = (t0 << 3) | (t1 << 2) | (t2 << 1) | (t3 << 0);
      }
      /*padding the odd-th elements and even-th elements separately*/
      for (i = 0; i < 128; i++) {
            state->A[i << 1] = tem[i];
            state->A[(i << 1)+1] = tem[i+128];
      }
}

/*de-group at the end of E_8:  it is the inverse of E8_initialgroup
  The 256 4-bit elements in state->A are degouped into the 1024-bit state->H
*/
void E8_finaldegroup(hashState *state) {
      unsigned int i;
      unsigned char t0,t1,t2,t3;
      unsigned char tem[256];

      for (i = 0; i < 128; i++) {
            tem[i] = state->A[i << 1];
            tem[i+128] = state->A[(i << 1)+1];
      }

      for (i = 0; i < 128; i++) state->H[i] = 0;

      for (i = 0; i < 256; i++) {
            t0 = (tem[i] >> 3) & 1;
            t1 = (tem[i] >> 2) & 1;
            t2 = (tem[i] >> 1) & 1;
            t3 = (tem[i] >> 0) & 1;

            state->H[i>>3] |= t0 << (7 - (i & 7));
            state->H[(i + 256)>>3] |= t1 << (7 - (i & 7));
            state->H[(i + 512)>>3] |= t2 << (7 - (i & 7));
            state->H[(i + 768)>>3] |= t3 << (7 - (i & 7));
      }
}

/*bijective function E8 */
void E8(hashState *state)
{
      unsigned int i;
      unsigned char t0,t1,t2,t3;
      unsigned char tem[256];

      /*initialize the round constant*/
      for (i = 0; i < 64; i++) state->roundconstant[i] = roundconstant_zero[i];

      /*initial group at the begining of E_8: group the H value into 4-bit elements and store them in A */
      E8_initialgroup(state);

      /* 42 rounds */
      for (i = 0; i < 42; i++) {
            R8(state);
            update_roundconstant(state);
      }

      /*de-group at the end of E_8:  decompose the 4-bit elements of A into the 1024-bit H*/
      E8_finaldegroup(state);
}

/* compression function F8 */
void F8(hashState *state)
{
      unsigned int i;

      /*xor the message with the first half of H*/
      for (i = 0; i < 64; i++) state->H[i] ^= state->buffer[i];

      /* Bijective function E8 */
      E8(state);

      /* xor the message with the last half of H */
      for (i = 0; i < 64; i++) state->H[i+64] ^= state->buffer[i];
}

/*before hashing a message, initialize the hash state as H0 */
HashReturn Init(hashState *state, int hashbitlen)
{
      unsigned int i;

      state->databitlen = 0;
	  state->datasize_in_buffer = 0;

      state->hashbitlen = hashbitlen;

      for (i = 0; i < 64; i++) state->buffer[i] = 0;
      for (i = 0; i < 128; i++) state->H[i] = 0;

      /*initialize the initial hash value of JH*/
      /*step 1: set H(-1) to the message digest size*/
      state->H[1] = hashbitlen & 0xff;
      state->H[0] = (hashbitlen >> 8) & 0xff;
	  /*step 2: compute H0 from H(-1) with message M(0) being set as 0*/
      F8(state);

      return(SUCCESS);
}

/*hash each 512-bit message block, except the last partial block*/
HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen)
{
      DataLength index; /*the starting address of the data to be compressed*/

      state->databitlen += databitlen;
      index = 0;

      /*if there is remaining data in the buffer, fill it to a full message block first*/
      /*we assume that the size of the data in the buffer is the multiple of 8 bits if it is not at the end of a message*/

      /*There is data in the buffer, but the incoming data is insufficient for a full block*/
      if ( (state->datasize_in_buffer > 0 ) && (( state->datasize_in_buffer + databitlen) < 512)  ) {
            if ( (databitlen & 7) == 0 ) {
                 memcpy(state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3)) ;
		    }
            else memcpy(state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3)+1) ;
            state->datasize_in_buffer += databitlen;
            databitlen = 0;
      }

      /*There is data in the buffer, and the incoming data is sufficient for a full block*/
      if ( (state->datasize_in_buffer > 0 ) && (( state->datasize_in_buffer + databitlen) >= 512)  ) {
	        memcpy( state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3) ) ;
	        index = 64-(state->datasize_in_buffer >> 3);
	        databitlen = databitlen - (512 - state->datasize_in_buffer);
	        F8(state);
	        state->datasize_in_buffer = 0;
      }

      /*hash the remaining full message blocks*/
      for ( ; databitlen >= 512; index = index+64, databitlen = databitlen - 512) {
            memcpy(state->buffer, data+index, 64);
            F8(state);
      }

      /*store the partial block into buffer, assume that -- if part of the last byte is not part of the message, then that part consists of 0 bits*/
      if ( databitlen > 0) {
            if ((databitlen & 7) == 0)
                  memcpy(state->buffer, data+index, (databitlen & 0x1ff) >> 3);
            else
                  memcpy(state->buffer, data+index, ((databitlen & 0x1ff) >> 3)+1);
            state->datasize_in_buffer = databitlen;
      }

      return(SUCCESS);
}


/*padding the message, truncate the hash value H and obtain the message digest*/
HashReturn Final(hashState *state, BitSequence *hashval)
{
      unsigned int i;

      if ( (state->databitlen & 0x1ff) == 0) {
            /*pad the message when databitlen is multiple of 512 bits, then process the padded block*/
            for (i = 0; i < 64; i++) state->buffer[i] = 0;
            state->buffer[0] = 0x80;
            state->buffer[63] = state->databitlen & 0xff;
            state->buffer[62] = (state->databitlen >> 8) & 0xff;
            state->buffer[61] = (state->databitlen >> 16) & 0xff;
            state->buffer[60] = (state->databitlen >> 24) & 0xff;
            state->buffer[59] = (state->databitlen >> 32) & 0xff;
            state->buffer[58] = (state->databitlen >> 40) & 0xff;
            state->buffer[57] = (state->databitlen >> 48) & 0xff;
            state->buffer[56] = (state->databitlen >> 56) & 0xff;
            F8(state);
      }
      else {
            /*set the rest of the bytes in the buffer to 0*/
            if ( (state->datasize_in_buffer & 7) == 0)
                   for (i = (state->databitlen & 0x1ff) >> 3; i < 64; i++)  state->buffer[i] = 0;
            else
                   for (i = ((state->databitlen & 0x1ff) >> 3)+1; i < 64; i++)  state->buffer[i] = 0;

            /*pad and process the partial block when databitlen is not multiple of 512 bits, then hash the padded blocks*/
            state->buffer[((state->databitlen & 0x1ff) >> 3)] |= 1 << (7- (state->databitlen & 7));
            F8(state);
            for (i = 0; i < 64; i++) state->buffer[i] = 0;
            state->buffer[63] = state->databitlen & 0xff;
            state->buffer[62] = (state->databitlen >> 8) & 0xff;
            state->buffer[61] = (state->databitlen >> 16) & 0xff;
            state->buffer[60] = (state->databitlen >> 24) & 0xff;
            state->buffer[59] = (state->databitlen >> 32) & 0xff;
            state->buffer[58] = (state->databitlen >> 40) & 0xff;
            state->buffer[57] = (state->databitlen >> 48) & 0xff;
            state->buffer[56] = (state->databitlen >> 56) & 0xff;
            F8(state);
      }

      /*trunacting the final hash value to generate the message digest*/
      switch (state->hashbitlen) {
            case 224:  memcpy(hashval,state->H+100,28);  break;
            case 256:  memcpy(hashval,state->H+96, 32);  break;
            case 384:  memcpy(hashval,state->H+80, 48);  break;
            case 512:  memcpy(hashval,state->H+64, 64);  break;
      }

      return(SUCCESS);
}


/* hash a message,
   three inputs: message digest size in bits (hashbitlen); message (data); message length in bits (databitlen)
   one output:   message digest (hashval)
*/
HashReturn Hash(int hashbitlen, const BitSequence *data,DataLength databitlen, BitSequence *hashval)
{
      hashState state;

      if ( hashbitlen == 224 || hashbitlen == 256 || hashbitlen == 384 || hashbitlen == 512 ) {
            Init(&state, hashbitlen);
            Update(&state, data, databitlen);
            Final(&state, hashval);
            return SUCCESS;
      }
      else
            return(BAD_HASHLEN);
}


Generated on Tue Nov 22 15:16:34 CET 2011
Home