Skip to content

Commit

Permalink
strict mode full test
Browse files Browse the repository at this point in the history
  • Loading branch information
yoann-dufresne committed Oct 8, 2024
1 parent 2cda9d4 commit 50b142d
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 29 deletions.
14 changes: 8 additions & 6 deletions app/avalanche.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -44,11 +44,13 @@ int main()
std::cout << hashFunc.to_string() << std::endl;

StrictAvalancheTest<myuint> 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;
}
8 changes: 4 additions & 4 deletions app/example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
99 changes: 80 additions & 19 deletions src/include/AvalancheTest.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()};
Expand Down Expand Up @@ -71,68 +71,129 @@ class StrictAvalancheTest
private:
// The hash function to test
HashFunction<myuint> m_hash_function;
size_t const nb_bits;
// Random number generator
std::random_device rd;
std::mt19937 gen;
std::uniform_int_distribution<myuint> dis;

// Storing structures for additive test
size_t next_bit_to_flip;
std::vector<std::vector<size_t>> m_diff_matrix;
size_t m_total_test;
public:
/** Constructor
*
* @param hash_function The hash function to test
*/
StrictAvalancheTest(HashFunction<myuint> hash_function) :
m_hash_function(hash_function),
gen(rd()), dis(0, (static_cast<size_t>(1) << hash_function.get_value_size()) - 1)
StrictAvalancheTest(HashFunction<myuint> hash_function)
: m_hash_function(hash_function), nb_bits(hash_function.get_value_size())
, gen(rd()), dis(0, (static_cast<size_t>(1) << nb_bits) - 1)
, next_bit_to_flip(0), m_diff_matrix(nb_bits, std::vector<size_t>(nb_bits, 0))
, m_total_test(0)
{ }

/** Run the test
*
* @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<std::vector<size_t>> diff_matrix(nb_bits, std::vector<size_t>(nb_bits, 0));

// Position of the bit to flip
size_t bit_position {0};

for (size_t i{0} ; i<nb_tests ; i++)
{
// Pick a random value A and hash it
myuint const A {dis(gen)};
myuint const hash_A {m_hash_function.apply(A)};

// flip a bit in A to get B and hash it
myuint const B {A ^ (static_cast<myuint>(1) << bit_position)};
myuint const B {A ^ (static_cast<myuint>(1) << next_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<nb_bits ; b_pos++)
{
diff_matrix[bit_position][b_pos] += diff & 1;
m_diff_matrix[next_bit_to_flip][b_pos] += diff & 1;
diff >>= 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<double>(m_total_test) / static_cast<double>(nb_bits * 2.0)};
for (size_t i{0} ; i<nb_bits ; i++)
{
for (size_t j{0} ; j<nb_bits ; j++)
{
// std::cout << "[" << m_diff_matrix[i][j] << "]";
double const diff {(static_cast<double>(m_diff_matrix[i][j]) - expected_diff) / expected_diff};
mean += (diff * diff) / static_cast<double>(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<nb_bits ; i++)
for (size_t j{0} ; j<nb_bits ; j++)
m_diff_matrix[i][j] = 0;

for (size_t i{0} ; i<(1UL<<nb_bits) ; i++)
{
if (i % 1000000 == 0) {
m_total_test = i*nb_bits+1;
std::cout << "\t" << i << " iterations:\t" << average_chi2() << std::endl;
}

myuint const A {i};
myuint const hash_A {m_hash_function.apply(A)};

for (size_t bit_to_flip{0} ; bit_to_flip<nb_bits ; bit_to_flip++)
{
// flip a bit in A to get B and hash it
myuint const B {A ^ (static_cast<myuint>(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<nb_bits ; b_pos++)
{
m_diff_matrix[bit_to_flip][b_pos] += diff & 1;
diff >>= 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<double>(m_total_test) / static_cast<double>(nb_bits * 2.0)};
for (size_t i{0} ; i<nb_bits ; i++)
{
for (size_t j{0} ; j<nb_bits ; j++)
{
// std::cout << "[" << diff_matrix[i][j] << "]";
double const diff {(diff_matrix[i][j] - expected_diff) / expected_diff};
// std::cout << "[" << m_diff_matrix[i][j] << "]";
double const diff {(static_cast<double>(m_diff_matrix[i][j]) - expected_diff) / expected_diff};
mean += (diff * diff) / static_cast<double>(nb_bits * nb_bits);
}
// std::cout << std::endl;
Expand Down

0 comments on commit 50b142d

Please sign in to comment.