/*\ \ / Average implementation of EnRUPT32 and EnRUPT64 in irRUPT stream hashing mode of operation for P=2 / \ Designed and implemented by Sean O'Neil \ / NIST SHA-3 submission by VEST Corporation / \ Released to the public domain by the author on November 1, 2008. \*/ #include "EnRUPT_avg.h" #ifdef _MSC_VER #pragma warning(disable:4090) /* p pointer is used as both input and output but separately, no need to scream */ #endif /* Single irreversible EnRUPT (ir1) round for any P and any w, reusable for any stream mode of operation */ #define ir1(x,i,i2,i4,i1,d,r,f,w) ((x)[i2]^=f=rotr(((x)[i]<<1)^(x)[i4]^d^r,w/4)*9,r+=2,d^=(x)[i1]^f) /* Two parallel rounds of (ir1) for P=2 and any w */ #define ir2(i,i2,i4,w) {ir1(s->x+4,i+1,i2,i4,i,s->x[0],s->x[2],f0,w);ir1(s->x+4,i,i2+1,i4+1,i+1,s->x[1],s->x[3],f1,w);} /* Complete (ir2), inputs a word every 2*s rounds if provided, produces a word of output every 2*s rounds if necessary, breaks out when done */ #define ir2io(i,i2,i4) {ir2(i,i2,i4,_ER_w_);if(!(s->x[2]&7)){if(!o){in_word(s->x,*p++);if(j--<=1)return;}else if(j--x[1]);if(j==-1)return;}else if(j+1==n)in_word(s->x,s->p[H]);}} /* Complete irRUPT mode implementation, hashing n words of p if o=0, otherwise sealing and returning o first words of keystream in p. */ static void EnRUPT (hashState *s, uw *p, const u32 H, const u32 n, const u32 o) { register uw f0,f1,q=0,i,j=n; for (;;) { for (i=0; i+4 < H; i+=2) ir2io(i,i+2,i+4); ir2io (i, i+2, 0); ir2io (i+2, 0, 2); } } HashReturn Init (hashState *state, int hashbitlen) /* once per message API initialization */ { memset (state, 0, sizeof(hashState)); state->H = (hashbitlen*2+2*_ER_w_-1)/_ER_w_&~1; /* 6 to 16*(s-1) words in the state */ if ((hashbitlen < 3*_ER_w_) || (hashbitlen > 8*(_ER_s_-1)*_ER_w_)) { state->n = -1; /* no entry to Update or Final */ return BAD_HASHBITLEN; /* this implementation cannot handle fewer than 6 words in the state */ } if (state->H & 1) { return BAD_HASHBITLEN; /* this implementation cannot handle odd state sizes correctly */ } state->hashbitlen = hashbitlen; state->x[3]++; return SUCCESS; } HashReturn Update (hashState *state, const BitSequence *data, DataLength databitlen) { size_t i = state->H*_ER_w_-state->n; if (state->n&7) return FAIL; /* unaligned bitwise hashing is not supported */ if (databitlen < i) /* not enough to fill up the block */ { memcpy (((u8*)(state->p))+(state->n>>3), data, (databitlen+7)>>3); state->n += (int)databitlen; return SUCCESS; /* nothing to process yet */ } if (state->n) /* any leftovers? */ { memcpy (((u8*)(state->p))+(state->n>>3), data, i>>3); EnRUPT (state, state->p, state->H, state->H, 0); /* processing the accumulated data first */ databitlen -= i; state->n = 0; } else i = 0; for (; databitlen >= (size_t)state->H*_ER_w_; databitlen -= state->H*_ER_w_, i += state->H*_ER_w_) { EnRUPT (state, (uw*)(data+(i>>3)), state->H, state->H, 0); } if ((int)databitlen) { memcpy (state->p, data+(i>>3), (databitlen+7)>>3); state->n = (int)databitlen; } return SUCCESS; } HashReturn Final (hashState *state, BitSequence *hashval) { register int i = state->n>>3, j = (state->n&7)^7, iri = 0; if (state->n < 0) return FAIL; /* and don't you come back no more! */ ((u8*)(state->p))[i] &= -1 << j; /* masking off possible garbage */ ((u8*)(state->p))[i] |= 1 << j; /* adding the padding bit */ memset (((u8*)(state->p))+i+1, 0, state->H*_ER_w_/8-i-1); /* and the sealing phase zeroes */ out_word(state->p[state->n/_ER_w_+1],state->hashbitlen); /* and the hash size in bit */ EnRUPT (state, state->p, state->H, state->H, 0); /* hashing in the last remaining bits, padded */ EnRUPT (state, (uw*)hashval, state->H, state->n/_ER_w_+(state->hashbitlen+_ER_w_-1)/_ER_w_+1, (state->hashbitlen+_ER_w_-1)/_ER_w_); state->n = -1; /* Hit the road, Jack! */ return SUCCESS; } HashReturn Hash (int hashbitlen, const BitSequence *data, DataLength databitlen, BitSequence *hashval) { hashState state; HashReturn i = Init (&state, hashbitlen); if (i != SUCCESS) return i; /* BAD_HASHBITLEN */ Update (&state, data, databitlen); return Final (&state, hashval); /* Init-Update-Final single call hashing */ }