diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/CMakeLists.txt | 26 | ||||
| -rw-r--r-- | src/algo/hash.c | 22 | ||||
| -rw-r--r-- | src/algo/hash.h | 10 | ||||
| -rw-r--r-- | src/algo/hash_test.c | 163 | ||||
| -rw-r--r-- | src/cmake_variables.h.in | 19 |
5 files changed, 240 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..7d3a91e --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,26 @@ +set(CRYPTOBENCHLIB_NAME cryptobench_lib) + +# Dependencies +# ... + +## Configuration Template +# This enables us to pull CMAKE variables into our source code, which is useful to keep things +# like versioning and naming consistent. +configure_file(cmake_variables.h.in ${CMAKE_SOURCE_DIR}/src/_gen/cmake_variables.h @ONLY) + +set(CRYPTOBENCHLIB_HEADERS + ${CMAKE_SOURCE_DIR}/src/_gen/cmake_variables.h + algo/hash.h) + +set(CRYPTOBENCHLIB_SOURCES + ${CRYPTOBENCHLIB_HEADERS} + algo/hash.c) + + +add_library(${CRYPTOBENCHLIB_NAME} STATIC ${CRYPTOBENCHLIB_SOURCES}) +set_target_properties(${CRYPTOBENCHLIB_NAME} PROPERTIES OUTPUT_NAME "cryptobench") + +target_include_directories(${CRYPTOBENCHLIB_NAME} + PRIVATE + ${CMAKE_SOURCE_DIR}/src +) diff --git a/src/algo/hash.c b/src/algo/hash.c new file mode 100644 index 0000000..c8ba66d --- /dev/null +++ b/src/algo/hash.c @@ -0,0 +1,22 @@ +#include "hash.h" +#include <stdint.h> + +uint64_t xor64_hash(uint64_t const *const bytes, size_t size) { + uint64_t result = 0; + + while (size != 0) { + result ^= bytes[size - 1]; + size--; + } + + return result; +} + +uint64_t djb2_hash(char const *const bytes, size_t size) { + uint64_t hash = 5381; + for (size_t i = 0; i < size; i++) { + hash = ((hash << 5) + hash) + bytes[i]; + } + + return hash; +} diff --git a/src/algo/hash.h b/src/algo/hash.h new file mode 100644 index 0000000..2b168b9 --- /dev/null +++ b/src/algo/hash.h @@ -0,0 +1,10 @@ +#ifndef CRYPTOBENCH_SRC_ALGO_HASH_H +#define CRYPTOBENCH_SRC_ALGO_HASH_H + +#include <stddef.h> +#include <stdint.h> + +uint64_t xor64_hash(uint64_t const *const bytes, size_t size); +uint64_t djb2_hash(char const *const bytes, size_t size); + +#endif diff --git a/src/algo/hash_test.c b/src/algo/hash_test.c new file mode 100644 index 0000000..6836c22 --- /dev/null +++ b/src/algo/hash_test.c @@ -0,0 +1,163 @@ +#include "algo/hash.h" +#include "unity.h" +#include <stdint.h> +#include <string.h> + +void test_xor_hash_consistency(void) { + uint64_t in[] = {10, 20, 30}; + + uint64_t actual_1 = xor64_hash(in, 3); + uint64_t actual_2 = xor64_hash(in, 3); + + TEST_ASSERT_EQUAL_INT(actual_1, actual_2); +} + +void test_xor_hash_empty_src(void) { + uint64_t in[] = {}; + + uint64_t actual = xor64_hash(in, 0); + + TEST_ASSERT_EQUAL_INT(0, actual); +} + +void test_xor_hash_single_byte(void) { + uint64_t in_1[] = {5}; + uint64_t in_2[] = {10}; + uint64_t in_3[] = {15}; + + uint64_t actual_1 = xor64_hash(in_1, 1); + uint64_t actual_2 = xor64_hash(in_2, 1); + uint64_t actual_3 = xor64_hash(in_3, 1); + + TEST_ASSERT_NOT_EQUAL(actual_1, actual_2); + TEST_ASSERT_NOT_EQUAL(actual_1, actual_3); + TEST_ASSERT_NOT_EQUAL(actual_2, actual_3); +} + +void test_xor_hash_is_varied(void) { + uint64_t in_1[] = {1, 2, 3}; + uint64_t in_2[] = {4, 5, 6}; + uint64_t in_3[] = {100, 200, 300}; + + uint64_t actual_1 = xor64_hash(in_1, 3); + uint64_t actual_2 = xor64_hash(in_2, 3); + uint64_t actual_3 = xor64_hash(in_3, 3); + + TEST_ASSERT_NOT_EQUAL(actual_1, actual_2); + TEST_ASSERT_NOT_EQUAL(actual_1, actual_3); + TEST_ASSERT_NOT_EQUAL(actual_2, actual_3); +} + +void test_xor_hash_permutation_collisions(void) { + uint64_t in_1[] = {1, 2}; + uint64_t in_2[] = {2, 1}; + + uint64_t actual_1 = xor64_hash(in_1, 2); + uint64_t actual_2 = xor64_hash(in_2, 2); + + TEST_ASSERT_EQUAL_INT(actual_1, actual_2); +} +void test_xor_hash_large_src(void) { + uint64_t large_array[100]; + for (int i = 0; i < 100; i++) { + large_array[i] = i * 7 + 13; + } + + uint64_t actual = xor64_hash(large_array, 100); + + TEST_ASSERT_NOT_EQUAL(0, actual); + + uint64_t actual_2 = xor64_hash(large_array, 100); + TEST_ASSERT_EQUAL_INT(actual, actual_2); +} +void test_xor_hash_range(void) { + uint64_t in[] = {10, 20, 30, 40, 50}; + + uint64_t hash_1 = xor64_hash(in, 1); + uint64_t hash_2 = xor64_hash(in, 2); + uint64_t hash_3 = xor64_hash(in, 3); + uint64_t hash_5 = xor64_hash(in, 5); + + TEST_ASSERT_NOT_EQUAL(hash_1, hash_2); + TEST_ASSERT_NOT_EQUAL(hash_2, hash_3); + TEST_ASSERT_NOT_EQUAL(hash_3, hash_5); +} + +void test_djb2_hash_consistency(void) { + const char *str = "Hello World!"; + uint64_t actual_1 = djb2_hash(str, strlen(str)); + uint64_t actual_2 = djb2_hash(str, strlen(str)); + + TEST_ASSERT_EQUAL_UINT64(actual_1, actual_2); +} + +void test_djb2_hash_empty_string(void) { + const char *str = ""; + uint64_t actual = djb2_hash(str, strlen(str)); + + TEST_ASSERT_EQUAL_UINT64(5381, actual); +} + +void test_djb2_hash_single_char(void) { + uint64_t hash_a = djb2_hash("a", 1); + uint64_t hash_b = djb2_hash("b", 1); + uint64_t hash_z = djb2_hash("z", 1); + + TEST_ASSERT_NOT_EQUAL(hash_a, hash_b); + TEST_ASSERT_NOT_EQUAL(hash_b, hash_z); +} + +void test_djb2_hash_known_values(void) { + // Pre-calculated djb2 hashes: + // e.g. "a": (5381 * 33) + 'a' = 177573 + 97 = 177670 + TEST_ASSERT_EQUAL_UINT64(0x0002b606ULL, djb2_hash("a", 1)); + TEST_ASSERT_EQUAL_UINT64(0x0b887389ULL, djb2_hash("foo", 3)); + TEST_ASSERT_EQUAL_UINT64(0x310D4F2079ULL, djb2_hash("Hello", 5)); +} + +void test_djb2_hash_different_strings(void) { + const char *str1 = "apple"; + const char *str2 = "banana"; + const char *str3 = "orange"; + + uint64_t hash1 = djb2_hash(str1, strlen(str1)); + uint64_t hash2 = djb2_hash(str2, strlen(str2)); + uint64_t hash3 = djb2_hash(str3, strlen(str3)); + + TEST_ASSERT_NOT_EQUAL(hash1, hash2); + TEST_ASSERT_NOT_EQUAL(hash1, hash3); + TEST_ASSERT_NOT_EQUAL(hash2, hash3); +} + +void test_djb2_hash_large_string(void) { + char long_str[256]; + for (int i = 0; i < 255; i++) { + long_str[i] = 'A' + (i % 26); + } + long_str[255] = '\0'; + + uint64_t actual = djb2_hash(long_str, strlen(long_str)); + TEST_ASSERT_NOT_EQUAL(5381, actual); + TEST_ASSERT_NOT_EQUAL(0, actual); + + uint64_t actual_2 = djb2_hash(long_str, strlen(long_str)); + TEST_ASSERT_EQUAL_UINT64(actual, actual_2); +} + +void test_runner_algo_hash(void) { + RUN_TEST(test_xor_hash_consistency); + RUN_TEST(test_xor_hash_empty_src); + RUN_TEST(test_xor_hash_single_byte); + RUN_TEST(test_xor_hash_is_varied); + RUN_TEST(test_xor_hash_permutation_collisions); + RUN_TEST(test_xor_hash_large_src); + RUN_TEST(test_xor_hash_range); + + RUN_TEST(test_djb2_hash_consistency); + RUN_TEST(test_djb2_hash_empty_string); + RUN_TEST(test_djb2_hash_single_char); + RUN_TEST(test_djb2_hash_known_values); + RUN_TEST(test_djb2_hash_different_strings); + RUN_TEST(test_djb2_hash_large_string); + return; +} diff --git a/src/cmake_variables.h.in b/src/cmake_variables.h.in new file mode 100644 index 0000000..0347d6a --- /dev/null +++ b/src/cmake_variables.h.in @@ -0,0 +1,19 @@ +#ifndef CPROJ_TEMPLATE_H +#define CPROJ_TEMPLATE_H + +#ifdef __GNUC__ +#define UNUSED(x) UNUSED_##x __attribute__((__unused__)) +#else +#define UNUSED(x) UNUSED_##x +#endif + +#ifdef __GNUC__ +#define UNUSED_FUNCTION(x) __attribute__((__unused__)) UNUSED_##x +#else +#define UNUSED_FUNCTION(x) UNUSED_##x +#endif + +#define CMAKE_PROJECT_VERSION "@PROJECT_VERSION@" +#define CMAKE_PROJECT_NAME "@PROJECT_NAME@" + +#endif |
