diff --git a/Makefile b/Makefile
index 667502879c38cfc7697ac408383a7742947bf3d6..713a2c44f0908058a8721c0511f6d4f21aa4299a 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ CC     = gcc
 CFLAGS = -Wall -std=c99 -g
 # modify the flags here ^
 EXE    = crack
-OBJ    = proj-2_sha256.o decrypt.o
+OBJ    = proj-2_sha256.o decrypt.o hashtable.o
 # add any new object files here ^
 # top (default) target
 all: $(EXE)
@@ -11,7 +11,6 @@ all: $(EXE)
 $(EXE): $(OBJ)
 	$(CC) $(CFLAGS) -o $(EXE) $(OBJ) -lm
 
-
 # ^ add any new dependencies here (for example if you add new modules)
 
 
diff --git a/decrypt.c b/decrypt.c
index 534fd48acc7ccdb638a5e08eaf829d4a1b17daa8..64b4b66b2a75a240b8e608621f03ef86c690bad9 100644
--- a/decrypt.c
+++ b/decrypt.c
@@ -1,4 +1,40 @@
 #include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+char** store_password_hashes(char* hashes){
+    char **password_hashes = (char**)malloc((strlen(hashes)/64)*sizeof(char*));
+    assert(password_hashes);
+    memset(password_hashes,0,(strlen(hashes)/64));
+    for(int i=1; i <= strlen(hashes)/64; i++){
+        password_hashes[i-1] = malloc(sizeof(char)*(64+1));
+        assert(password_hashes[i-1]);
+        memset(password_hashes[i-1],0,strlen(password_hashes[i-1]));
+        snprintf(password_hashes[i-1], 65, "%s",hashes + (i-1)*64);
+    }
+    return password_hashes;
+}
+
+void read_hash_file(FILE *file){
+    if (file){
+        char hashes[650];
+        int n=0;
+        int c;
+        while((c = getc(file)) != EOF){
+            n +=sprintf(hashes+n,"%02x", c);
+        }
+        // printf("%s",hashes);
+        char **words = store_password_hashes(hashes);
+        for(int i=0; i < strlen(hashes)/64; i++){
+            printf("%d:    %s\n", i, words[i]);
+            free(words[i]);
+        };
+        free(words);
+        fclose(file);
+    }
+}
+void generate_guesses(int n_guesses){
+}
 
 int main(int argc, char *argv[]){
     FILE *file;
@@ -15,16 +51,3 @@ int main(int argc, char *argv[]){
         // read file and do stuff
     }
 }
-void read_hash_file(FILE *file){
-    int c;
-    if (file){
-        while((c = getc(file)) != EOF){
-            putchar(c);
-        }
-        fclose(file);
-    }
-}
-
-
-void generate_guesses(int n_guesses){
-}
\ No newline at end of file
diff --git a/hashtable.c b/hashtable.c
new file mode 100644
index 0000000000000000000000000000000000000000..6052f84d89030fcb190b5f3625ca988529880771
--- /dev/null
+++ b/hashtable.c
@@ -0,0 +1,176 @@
+/* This hash table has been adapted by Abhisha Nirmalathas.
+	The original hash table it was adapted from was made
+ by Matt Farrugia <matt.farrugia@unimelb.edu.au, for Design of Algorithms.
+ This hash table uses separate chaining with an array.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include "hashtable.h"
+
+typedef struct bucket Bucket;
+struct bucket {
+	char **keys; //array of words
+	int *values; //array of weighted frequencies, lower value is higher frequency
+	int capacity; //space available in bucket
+	int n_elems; //number of elements in bucket
+};
+
+struct table {
+	int size; //number of buckets
+	Bucket *buckets; //list of buckets
+};
+
+/************************************************************************/
+// moves recently accessed key & value to the front of bucket
+void move_to_front(Bucket *bucket, int hash_value);
+
+ unsigned int seed = 73802;
+ unsigned int xor_hash(const char *key, unsigned int size) {
+ 	unsigned int h = seed;
+
+ 	int i;
+ 	for (i = 0; key[i] != '\0'; i++) {
+ 		h = h ^ ((h << 5) + key[i] + (h >> 2));
+ 	}
+
+ 	return h % size;
+ }
+/************************************************************************/
+Bucket *add_to_bucket(Bucket *bucket, char *key, int value) {
+	/*Adds new key and value to existing bucket*/
+	bucket->n_elems = bucket->n_elems + 1;
+	// allocates more memory if not enough space
+	if (bucket->capacity <= bucket->n_elems){
+		bucket->capacity = 2*(bucket->capacity + 1);
+		bucket->keys = realloc(bucket->keys,sizeof(char*) * (bucket->capacity));
+		bucket->values = realloc(bucket->values,sizeof(int) * (bucket->capacity));
+	}
+	assert(bucket->keys);
+	assert(bucket->values);
+	//adds new key and avlue to end of bucket
+	bucket->values[bucket->n_elems-1] = value;
+	bucket->keys[bucket->n_elems-1] = key;
+	return bucket;
+}
+/************************************************************************/
+// Warning: does not free bucket->next
+void free_bucket(Bucket bucket) {
+	/*Deallocates memory in bucket*/
+	free(bucket.keys);
+	free(bucket.values);
+}
+
+
+/************************************************************************/
+HashTable *new_hash_table(int size) {
+	/*Builds a new hash table of input size*/
+	HashTable *table = malloc(sizeof *table);
+	assert(table);
+	table->size = size;
+	table->buckets = malloc(size * (sizeof *table->buckets));
+	assert(table->buckets);
+	int i;
+	for (i = 0; i < size; i++) {
+		table->buckets[i].keys = malloc(sizeof(char*));
+		table->buckets[i].values = malloc(sizeof(int));
+		table->buckets[i].capacity = 0;
+		table->buckets[i].n_elems = 0;
+	}
+	return table;
+}
+/************************************************************************/
+void free_hash_table(HashTable *table) {
+	/*Deallocates memory from hash table*/
+	assert(table != NULL);
+	int i;
+	for (i = 0; i < table->size; i++) {
+		free_bucket(table->buckets[i]);
+	}
+	free(table->buckets);
+	free(table);
+}
+
+/************************************************************************/
+bool equal(char *a, char *b) {
+	/*Returns if a string is equal to another string*/
+	return strcmp(a, b) == 0;
+}
+
+/************************************************************************/
+void hash_table_put(HashTable *table, char *key, int value) {
+	/*Inserts new key into hash table with weighted value*/
+	assert(table != NULL);
+	assert(key != NULL);
+	int hash_value = xor_hash(key, table->size);
+	// look for existing key
+	Bucket *bucket = &table->buckets[hash_value];
+	for (int i=0; i < bucket->n_elems; i++){
+		if (equal(bucket->keys[i], key)){
+			bucket->values[i] = value;
+			move_to_front(bucket, i);
+			return;
+		}
+	}
+	// adds key and value as not in hash table
+	bucket = add_to_bucket(bucket, key, value);
+	table->buckets[hash_value] = *bucket;
+	move_to_front(bucket, bucket->n_elems - 1);
+}
+/************************************************************************/
+void move_to_front(Bucket *bucket, int index){
+	/*moves recently accessed key & value to the front of bucket*/
+	char* temp_key;
+	int temp_value;
+	if (bucket->n_elems <= 1 && index >= bucket->n_elems){
+		return;
+	}
+	// swaps position of first element with recently accessed
+	temp_key = bucket->keys[index];
+	temp_value = bucket->values[index];
+	bucket->keys[index] = bucket->keys[0];
+	bucket->values[index] = bucket->values[0];
+	bucket->values[0] = temp_value;
+	bucket->keys[0] = temp_key;
+}
+/************************************************************************/
+int hash_table_get(HashTable *table, char *key) {
+	/*Checks if key in hash table and returns value if present*/
+	int freq = -1;
+	assert(table != NULL);
+	assert(key != NULL);
+
+	int hash_value = xor_hash(key, table->size);
+
+	// look for existing key
+	Bucket *bucket = &table->buckets[hash_value];
+	for (int i=0; i < bucket->n_elems; i++){
+		if (equal(bucket->keys[i], key)){
+			freq = bucket->values[i];
+			move_to_front(bucket, i);
+			break;
+		}
+	}
+	//returns value of key if found, else return -1
+	return freq;
+}
+/************************************************************************/
+bool hash_table_has(HashTable *table, char *key) {
+	/*Checks if the key exists in hash table*/
+	assert(table != NULL);
+	assert(key != NULL);
+
+	int hash_value = xor_hash(key, table->size);
+
+	// look for existing key
+	Bucket *bucket = &table->buckets[hash_value];
+	for (int i=0; i < bucket->n_elems; i++){
+		if (equal(bucket->keys[i], key)){
+			return true;
+		}
+	}
+	return false;
+}
diff --git a/hashtable.h b/hashtable.h
new file mode 100644
index 0000000000000000000000000000000000000000..a7bff387af7db8ce86c6d7a97f7ef294fb25023e
--- /dev/null
+++ b/hashtable.h
@@ -0,0 +1,24 @@
+/* This hash table has been adapted by Abhisha Nirmalathas.
+	The original hash table it was adapted from was made
+ by Matt Farrugia <matt.farrugia@unimelb.edu.au, for Design of Algorithms.
+ This hash table uses separate chaining with an array.
+*/
+#include <stdbool.h>
+
+typedef struct table HashTable;
+
+
+//Creates a new hash table of input size
+HashTable *new_hash_table(int size);
+
+//Deallocates memory from hash table
+void free_hash_table(HashTable *table);
+
+//Inserts new key into hash table with weighted value
+void hash_table_put(HashTable *table, char *key, int value);
+
+//checks if key in hash table and returns value if present
+int hash_table_get(HashTable *table, char *key);
+
+//Checks if the key exists in hash table
+bool hash_table_has(HashTable *table, char *key);