/* hashlib.c -- hash function library for problem set 1 in
                6.857 [Fall 2001].  Much of this code hash 
				been copied from RC5REF.C.           */ 
/* RC5REF.C -- Reference implementation of RC5-32/12/16 in C.        */
/* Copyright (C) 1995 RSA Data Security, Inc.                        */

#include <stdio.h>
#include <time.h>
#include "hashlib.h"

#define w        16             /* word size in bits                 */
#define r        12             /* number of rounds                  */  
#define b         8             /* number of bytes in key            */
#define c         4             /* number  words in key              */
                                /* c = max(1,ceil(8*b/w))            */
#define t        26             /* size of table S = 2*(r+1) words   */
WORD S[t];                      /* expanded key table                */
WORD P = 0xb7e1, Q = 0x9e37;  /* magic constants             */

/* Rotation operators. x must be unsigned, to get logical right shift*/
#define ROTL(x,y) (((x)<<(y&(w-1))) | ((x)>>(w-(y&(w-1)))))
#define ROTR(x,y) (((x)>>(y&(w-1))) | ((x)<<(w-(y&(w-1)))))

void printword(WORD A)
{ 
	WORD k;
	for (k=0;k<w;k+=8) printf("%02.2lX",(A>>k)&0xFF);
}

void RC5_ENCRYPT(WORD *pt, WORD *ct) /* 2 WORD input pt/output ct    */
{ 
	WORD i, A=(WORD)(pt[0]+S[0]), B=(WORD)(pt[1]+S[1]);
	for (i=1; i<=r; i++) { 
		A = (WORD)(ROTL( (A^B),B)+S[2*i]); 
		B = (WORD)(ROTL( (B^A),A)+S[2*i+1]); 
    }
	ct[0] = A; ct[1] = B;  
} 

void RC5_DECRYPT(WORD *ct, WORD *pt) /* 2 WORD input ct/output pt    */
{ 
	WORD i, B=ct[1], A=ct[0], C;
	for (i=r; i>0; i--) { 
		C = (WORD)(B-S[2*i+1]);
		B = ROTR( C , A) ^ A; 
		C = (WORD)(A-S[2*i]);
		A = ROTR( C , B) ^ B; 
    }
	pt[1] = (WORD)(B-S[1]); pt[0] = (WORD)(A-S[0]);  
} 

void RC5_SETUP(unsigned char *K) /* secret input key K[0...b-1]      */
{ 
	unsigned int i;
	WORD  j, k, u=w/8, A, B, C, D, E, F, L[c]; 
	/* Initialize L, then S, then mix key into S */
	for (i=b-1,L[c-1]=0; i!=-1; i--) L[i/u] = (L[i/u]<<8)+K[i];
	
	for (S[0]=P,i=1; i<t; i++) {
		S[i] = S[i-1]+Q;
	}

	for (A=B=i=j=k=0; k<3*t; k++,i=(i+1)%t,j=(j+1)%c) {   /* 3*t > 3*c */
		C = (WORD)(A+B);
		C = (WORD)(S[i]+C);
		A = S[i] = ROTL(C,3);  
		C = (WORD)(A+B);
		D = (WORD)(L[j]+C);
		B = L[j] = ROTL(D, C); 
	} 

} 

void hash(char *msg, WORD *out) /* input is msg. out[2] holds the digest */
{
	int i=0,j,n;
	unsigned char key[b];
	WORD tmp[2] = {1,2};

	n = strlen(msg);

	while(i<n) {
		for(j=0; j<b && i<n; i++,j++) {
			key[j] = msg[i];
		}
		for(; j<b; j++) { key[j] = 0; } /* pad key with zero */

		RC5_SETUP(key);
		RC5_ENCRYPT(tmp, tmp);
	}
	
	out[0] = tmp[0]; out[1] = tmp[1];

}

