Skip to content

Commit

Permalink
✨ Avalanche matrix computation command
Browse files Browse the repository at this point in the history
  • Loading branch information
yoann-dufresne committed Nov 21, 2024
1 parent 57da1e9 commit be78898
Show file tree
Hide file tree
Showing 2 changed files with 278 additions and 32 deletions.
174 changes: 142 additions & 32 deletions app/avalanche.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <iostream>
#include <cstdint>
#include <memory>
#include <eo>

#include "AvalancheTest.hpp"
#include "HashFunction.hpp"
Expand All @@ -14,46 +15,155 @@
#include "log.h"


int main()
int main(int argc, char* argv[])
{
// --- Argument parser ---

eoParser argparser(argc, argv);

const std::string hashfile = argparser.createParam<std::string>("hash_functions.txt", "hash-file",
"Path to the file containing the hash functions to test", 'f', "IO", true).value();
const std::string outfile = argparser.createParam<std::string>("", "outfile",
"File where the matricies will be outputed", 'o', "IO").value();

const size_t nb_tests = argparser.createParam<size_t>(0, "num-tests",
"The number of tests to perform on the hash functions. If 0, perform a complete avalanche test",
'n', "sampling").value();

make_help(argparser);

std::cout << "Hash functions file: " << hashfile << std::endl;
std::cout << "Output file: " << outfile << std::endl;


CLUTCHLOG(progress, "Set config");
clutchlog_config(); // common config
auto& log = clutchlog::logger();
log.threshold("XDebug");

// The size of the values to manipulate is 57 bits.
size_t value_size{32};
// Max size will be 63 bits (1 more bit needed for mult).
using myuint = uint64_t;

// --- Preparation to file reading ---

CLUTCHLOG(progress, "Open hash functions file");
// Open the file containing the hash functions that we want to test
std::ifstream file(hashfile);
if (!file.is_open())
{
CLUTCHLOG(critical, "Could not open the file " << hashfile);
return 1;
}

// Read the number of hash functions that are present in the file
std::string line{};
while (line.size() == 0 or line[0] == '#')
{
std::getline(file, line);
}

size_t num_functions {std::stoul(line)};
if (num_functions == 0)
{
CLUTCHLOG(critical, "No hash function to test in the file " << hashfile);
return 1;
}
CLUTCHLOG(note, num_functions << " hash functions will be tested");

// --- Hash function testing ---
for (size_t idx{0} ; idx < num_functions ; idx++)
{
// Read until we find a line that is not a comment or a spacer
line = "";
while (line.size() == 0 or line[0] == '#')
{
std::getline(file, line);
}

// Get the parameters from the line. Format is: num_bits num_operators operator1 param1 [... operatorN paramN]
std::istringstream iss{line};
size_t num_bits, num_operators;
iss >> num_bits;
iss >> num_operators;
if (num_bits == 0)
{
CLUTCHLOG(critical, "The number of bits for the hash function is 0");
return 1;
}
if (num_operators == 0)
{
CLUTCHLOG(critical, "The hash function declare 0 operators");
return 1;
}

// --- Create the function ---
HashFunction<myuint> hashFunc(num_bits, "hash");

// Read and add the operators to the hash function
for (size_t op_idx{0} ; op_idx<num_operators ; op_idx++)
{
// Read the type and parameter of the operator
std::string op_name;
iss >> op_name;
uint64_t param;
iss >> param;

// Instanciate the operator
if (op_name == "XSR")
{
hashFunc.add_operator(std::make_unique<XorRightShift<myuint>>(param, num_bits));
}
else if (op_name == "XSL")
{
hashFunc.add_operator(std::make_unique<XorLeftShift<myuint>>(param, num_bits));
}
else if (op_name == "MUL")
{
hashFunc.add_operator(std::make_unique<Multiply<myuint>>(param, num_bits));
}
else if (op_name == "ASL")
{
hashFunc.add_operator(std::make_unique<AddShift<myuint>>(param, num_bits));
}
else
{
CLUTCHLOG(critical, "Unknown operator: " << op_name);
return 1;
}
}
// Complete the function with masks
hashFunc.complete_with_masks();

// Print the string representation of the hash function
std::cout << hashFunc.to_string() << std::endl;

// --- Avalanche test ---
std::unique_ptr<AvalancheTest<myuint>> test;
if (nb_tests == 0)
{
CLUTCHLOG(note, "Full avalanche test");
test = std::make_unique<FullAvalancheTest<myuint>>(num_bits);
}
else
{
CLUTCHLOG(note, "Sampling avalanche test (" << nb_tests << " tests)");
test = std::make_unique<SamplingAvalancheTest<myuint>>(num_bits, nb_tests);
}
test->set_hash_function(hashFunc);
auto result = (*test)();
CLUTCHLOG(progress, "Hash function " << idx << " - Avalanche test (sampling: " << nb_tests << "): " << result);

CLUTCHLOG(progress, "Try HashFunc");
// Create an instance of HashFunction with a value size of 64 bits
HashFunction<myuint> hashFunc(value_size, "hash");

// Add shift operators
// Should be [16 7feb352d 15 846ca68b 16] = 0.17353355999581582 * 10^-3
// Computed = 0.000173532 (2^32 iterations)
hashFunc.add_operator(std::make_unique<XorRightShift<myuint>>(16, value_size));
hashFunc.add_operator(std::make_unique<Multiply<myuint>>(0x7feb352dU, value_size));
hashFunc.add_operator(std::make_unique<XorRightShift<myuint>>(15, value_size));
hashFunc.add_operator(std::make_unique<Multiply<myuint>>(0x846ca68bU, value_size));
hashFunc.add_operator(std::make_unique<XorRightShift<myuint>>(16, value_size));

CLUTCHLOG(note, "Complete with masks");
// Complete with masks if necessary
hashFunc.complete_with_masks();

// Print the string representation of the hash function
std::cout << hashFunc.to_string() << std::endl;

FullAvalancheTest<myuint> full_test{value_size};
full_test.set_hash_function(hashFunc);
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));
// }
std::cout << "Test completed " << full_test() << std::endl;
// --- Output the matrix ---
if (outfile.size() > 0)
{
std::ofstream out(outfile, std::ios::app);
test->print_matrix(out);
}
else
{
test->print_matrix(std::cout);
}
}

return 0;
}
136 changes: 136 additions & 0 deletions app/brutforce.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#include <iostream>
#include <cstdint>
#include <cassert>
#include <vector>
#include <string>

#include <eo>

#include "HashFunction.hpp"
#include "Operator.hpp"
#include "XorLeftShift.hpp"
#include "XorRightShift.hpp"
#include "Multiply.hpp"
#include "AddShift.hpp"
#include "Masking.hpp"
#include "AvalancheTest.hpp"

/* In this application we enumerates all the possible reversible hash functions for a certain number of bits and a
* fixed number of operations. For each of such function we perform an avalanche test and keep only the ones that
* have the best score.
*/


// class CombinationIterator {
// public:
// CombinationIterator(const std::vector<std::string>& list, int size)
// : list(list), size(size), indices(size, 0), finished(list.size() < size)
// {}

// // Begin iterator
// CombinationIterator begin() {
// return *this;
// }

// // End iterator
// CombinationIterator end() {
// CombinationIterator endIterator = *this;
// endIterator.finished = true;
// return endIterator;
// }

// // Move to the next combination
// CombinationIterator& operator++() {
// if (!advance()) {
// finished = true;
// }
// return *this;
// }

// // Compare two iterators
// bool operator!=(const CombinationIterator& other) const {
// return finished != other.finished;
// }

// // Access the current combination
// std::vector<std::string> operator*() const {
// std::vector<std::string> combination;
// for (int idx : indices) {
// combination.push_back(list[idx]);
// }
// return combination;
// }

// private:
// const std::vector<std::string>& list; // List of elements
// int size; // Combination size
// std::vector<int> indices; // Current indices
// bool finished; // Indicates if all combinations have been generated

// // Advance to the next combination
// bool advance() {
// int total = list.size();

// for (int i = size - 1; i >= 0; --i) {
// if (indices[i] < total - 1) {
// ++indices[i];
// for (int j = i + 1; j < size; ++j) {
// indices[j] = 0;
// }
// return true;
// }
// }

// return false; // No more combinations
// }
// };


int main(int argc, char* argv[])
{
// eoParser argparser(argc, argv);

// /***** Classical arguments *****/

// const std::string log_level = argparser.createParam<std::string>("Progress", "log-level",
// "Maximum depth level of logging (Critical<Error<Warning<Progress<Note<Info<Debug<XDebug)", 'l', "Logging").value();

// const std::string log_file = argparser.createParam<std::string>(".*", "log-file",
// "Regexp indicating which source file is allowed logging (use '.*' to allow all)", 'f', "Logging").value();

// const std::string log_func = argparser.createParam<std::string>(".*", "log-func",
// "Regexp indicating which function is allowed logging (use '.*' to allow all)", 'F', "Logging").value();

// const size_t log_depth = argparser.createParam<size_t>(std::numeric_limits<size_t>::max(), "log-depth",
// "Maximum stack depth above which logging is not allowed (the larger, the more is displayed)", 'D', "Logging").value();


// clutchlog_config(); // common config
// auto& log = clutchlog::logger();
// ASSERT(log.levels().contains(log_level));
// log.threshold(log_level);
// log.depth(log_depth);
// log.file(log_file);
// log.func(log_func);
// CLUTCHLOG(progress, "Set config...");


// // Brutforce parameters
// size_t value_size{8};
// size_t func_len{2};

// // List of operator classes
// std::vector<std::string> operators{"XorLeftShift", "XorRightShift", "AddShift", "Multiply"};

// for (auto& comb : CombinationIterator(operators, func_len))
// {
// CLUTCHLOG(note, "Combination:");
// for (auto& op : comb)
// {
// CLUTCHLOG(note, " " << op);
// }
// }

return 0;
}

0 comments on commit be78898

Please sign in to comment.