From 50b142d4deb6f43088847299e2afd42a8ff1b4e3 Mon Sep 17 00:00:00 2001 From: yoann-dufresne Date: Tue, 8 Oct 2024 23:06:55 +0200 Subject: [PATCH] strict mode full test --- app/avalanche.cpp | 14 ++--- app/example.cpp | 8 +-- src/include/AvalancheTest.hpp | 99 ++++++++++++++++++++++++++++------- 3 files changed, 92 insertions(+), 29 deletions(-) diff --git a/app/avalanche.cpp b/app/avalanche.cpp index 83eaa37..8534a4a 100644 --- a/app/avalanche.cpp +++ b/app/avalanche.cpp @@ -23,7 +23,7 @@ int main() // The size of the values to manipulate is 57 bits. size_t value_size{32}; - using myuint = uint32_t; + using myuint = uint64_t; CLUTCHLOG(progress, "Try HashFunc"); // Create an instance of HashFunction with a value size of 64 bits @@ -44,11 +44,13 @@ int main() std::cout << hashFunc.to_string() << std::endl; StrictAvalancheTest strict_test{hashFunc}; - CLUTCHLOG(progress, "Run SoftAvalancheTest"); - for (size_t i = 0; i < 20; i++) - { - CLUTCHLOG(note, " 10 000 iterations:\t" << strict_test.run(value_size * 10000UL)); - } + CLUTCHLOG(progress, "Run StrictAvalancheTest incrementaly"); + // size_t const step_size {10000}; + // for (size_t iteration = step_size; iteration <= 1000000000UL; iteration += step_size) + // { + // CLUTCHLOG(note, "\t" << iteration << " iterations:\t" << strict_test.run(step_size)); + // } + strict_test.run_exact_test(); return 0; } diff --git a/app/example.cpp b/app/example.cpp index e309580..abd309f 100644 --- a/app/example.cpp +++ b/app/example.cpp @@ -59,20 +59,20 @@ int main() CLUTCHLOG(progress, "Run SoftAvalancheTest"); for (size_t i = 0; i < 20; i++) { - CLUTCHLOG(note, " 10 000 iterations:\t" << strict_test.run(value_size * 10000UL)); + CLUTCHLOG(note, " 10 000 iterations:\t" << strict_test.run_random_tests(value_size * 10000UL)); } std::cout << std::endl; for (size_t i = 0; i < 20; i++) { - CLUTCHLOG(note, " 100 000 iterations:\t" << strict_test.run(value_size * 100000UL)); + CLUTCHLOG(note, " 100 000 iterations:\t" << strict_test.run_random_tests(value_size * 100000UL)); } std::cout << std::endl; std::cout << std::endl; for (size_t i = 0; i < 20; i++) { - CLUTCHLOG(note, " 1 000 000 iterations:\t" << strict_test.run(value_size * 1000000UL)); + CLUTCHLOG(note, " 1 000 000 iterations:\t" << strict_test.run_random_tests(value_size * 1000000UL)); } - CLUTCHLOG(note, "100 000 000 iterations:\t" << strict_test.run(value_size * 100000000UL)); + CLUTCHLOG(note, "100 000 000 iterations:\t" << strict_test.run_random_tests(value_size * 100000000UL)); CLUTCHLOG(note, "Invert"); // Get the inverse function diff --git a/src/include/AvalancheTest.hpp b/src/include/AvalancheTest.hpp index 1e7004a..438c323 100644 --- a/src/include/AvalancheTest.hpp +++ b/src/include/AvalancheTest.hpp @@ -31,7 +31,7 @@ class SoftAvalancheTest * @param nb_tests The number of tests to run * @return The percentage of bits that changed */ - double run(size_t nb_tests) + double run_random_tests(size_t nb_tests) { // Number of bits where the function is encoded size_t const nb_bits {m_hash_function.get_value_size()}; @@ -71,19 +71,26 @@ class StrictAvalancheTest private: // The hash function to test HashFunction m_hash_function; + size_t const nb_bits; // Random number generator std::random_device rd; std::mt19937 gen; std::uniform_int_distribution dis; + // Storing structures for additive test + size_t next_bit_to_flip; + std::vector> m_diff_matrix; + size_t m_total_test; public: /** Constructor * * @param hash_function The hash function to test */ - StrictAvalancheTest(HashFunction hash_function) : - m_hash_function(hash_function), - gen(rd()), dis(0, (static_cast(1) << hash_function.get_value_size()) - 1) + StrictAvalancheTest(HashFunction hash_function) + : m_hash_function(hash_function), nb_bits(hash_function.get_value_size()) + , gen(rd()), dis(0, (static_cast(1) << nb_bits) - 1) + , next_bit_to_flip(0), m_diff_matrix(nb_bits, std::vector(nb_bits, 0)) + , m_total_test(0) { } /** Run the test @@ -91,16 +98,8 @@ class StrictAvalancheTest * @param nb_tests The number of tests to run * @return The percentage of bits that changed */ - double run(size_t nb_tests) + double run_random_tests(size_t nb_tests) { - // Number of bits where the function is encoded - size_t const nb_bits {m_hash_function.get_value_size()}; - // Difference matrix - std::vector> diff_matrix(nb_bits, std::vector(nb_bits, 0)); - - // Position of the bit to flip - size_t bit_position {0}; - for (size_t i{0} ; i(1) << bit_position)}; + myuint const B {A ^ (static_cast(1) << next_bit_to_flip)}; myuint const hash_B {m_hash_function.apply(B)}; myuint diff {hash_A ^ hash_B}; @@ -116,23 +115,85 @@ class StrictAvalancheTest // Register the output bits that changed for (size_t b_pos{0} ; b_pos>= 1; } // Move to the next bit to flip in the next iteration - bit_position = (bit_position + 1) % nb_bits; + next_bit_to_flip = (next_bit_to_flip + 1) % nb_bits; } + m_total_test += nb_tests; + + // Xi² average test + double mean {0}; + double const expected_diff {static_cast(m_total_test) / static_cast(nb_bits * 2.0)}; + for (size_t i{0} ; i(m_diff_matrix[i][j]) - expected_diff) / expected_diff}; + mean += (diff * diff) / static_cast(nb_bits * nb_bits); + } + // std::cout << std::endl; + } + + // Return the percentage of bits that changed + return sqrt(mean); + } + + /** Run the test + * + * @return The percentage of bits that changed + */ + double run_exact_test() + { + for (size_t i{0} ; i(1) << bit_to_flip)}; + myuint const hash_B {m_hash_function.apply(B)}; + + myuint diff {hash_A ^ hash_B}; + + // Register the output bits that changed + for (size_t b_pos{0} ; b_pos>= 1; + } + } + } + + return average_chi2(); + } + + double average_chi2() + { // Xi² average test double mean {0}; - double const expected_diff {nb_tests / (nb_bits * 2.0)}; + double const expected_diff {static_cast(m_total_test) / static_cast(nb_bits * 2.0)}; for (size_t i{0} ; i(m_diff_matrix[i][j]) - expected_diff) / expected_diff}; mean += (diff * diff) / static_cast(nb_bits * nb_bits); } // std::cout << std::endl;