Skip to content

Commit

Permalink
❇️ brutforce 8bits 3 op
Browse files Browse the repository at this point in the history
  • Loading branch information
yoann-dufresne committed Nov 22, 2024
1 parent be78898 commit b1d057e
Show file tree
Hide file tree
Showing 6 changed files with 342 additions and 97 deletions.
1 change: 0 additions & 1 deletion app/avalanche.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ int main(int argc, char* argv[])
std::cout << "Output file: " << outfile << std::endl;


CLUTCHLOG(progress, "Set config");
clutchlog_config(); // common config
auto& log = clutchlog::logger();
log.threshold("XDebug");
Expand Down
328 changes: 232 additions & 96 deletions app/brutforce.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include <cassert>
#include <vector>
#include <string>
#include <sstream>
#include <unordered_map>

#include <eo>

Expand All @@ -21,115 +23,249 @@
*/


// 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
// }
// };
class CombinationIterator {
public:
CombinationIterator(const std::vector<std::string>& list, size_t const size)
: list(list), size(size), indices(size, 0), finished(list.size() < size)
{}

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

int main(int argc, char* argv[])
// 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
}
};


double test_hash_function(size_t const value_size, std::vector<std::string> const& operators, std::vector<uint64_t> const& parameters)
{
// eoParser argparser(argc, argv);
// Create the hash function
HashFunction<uint64_t> hashFunc(value_size, "hash");

// Add the operators to the hash function
for (size_t i = 0; i < operators.size(); ++i)
{
if (operators[i] == "XorLeftShift")
{
hashFunc.add_operator(std::make_unique<XorLeftShift<uint64_t>>(parameters[i], value_size));
}
else if (operators[i] == "XorRightShift")
{
hashFunc.add_operator(std::make_unique<XorRightShift<uint64_t>>(parameters[i], value_size));
}
else if (operators[i] == "AddShift")
{
hashFunc.add_operator(std::make_unique<AddShift<uint64_t>>(parameters[i], value_size));
}
else if (operators[i] == "Multiply")
{
hashFunc.add_operator(std::make_unique<Multiply<uint64_t>>(parameters[i], value_size));
}
else
{
std::cerr << "Unknown operator: " << operators[i] << std::endl;
return 0;
}
}

hashFunc.complete_with_masks();


// Perform the avalanche test
FullAvalancheTest<uint64_t> test(value_size);
test.set_hash_function(hashFunc);
double score = test();

return score;
}


struct ParamLimits {
uint64_t min;
uint64_t max;
uint64_t step;
};


// /***** Classical arguments *****/
class ParamEnumerator {
public:
ParamEnumerator(size_t const value_size, std::vector<std::string> const& operators)
: value_size(value_size), operators(operators), params(operators.size(), 0), finished(operators.size() == 0)
{
operators_parameters["XorLeftShift"] = {1, value_size - 1, 1};
operators_parameters["XorRightShift"] = {1, value_size - 1, 1};
operators_parameters["AddShift"] = {1, value_size - 1, 1};

// 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();
uint64_t const max_value {(~static_cast<uint64_t>(0)) >> (sizeof(uint64_t) * 8 - value_size)};
operators_parameters["Multiply"] = {3, max_value, 2};

// 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();
for (size_t i = 0; i < operators.size(); ++i) {
params[i] = operators_parameters[operators[i]].min;
}
}

// 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();
// Begin iterator
ParamEnumerator begin() {
return *this;
}

// 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();
// End iterator
ParamEnumerator end() {
ParamEnumerator endIterator = *this;
endIterator.finished = true;
return endIterator;
}

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

// 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...");
// Compare two iterators
bool operator!=(const ParamEnumerator& other) const {
return finished != other.finished;
}

// Access the current combination
std::vector<uint64_t> operator*() const {
std::vector<uint64_t> parameters;
for (int param : params) {
parameters.push_back(param);
}
return parameters;
}

// // Brutforce parameters
// size_t value_size{8};
// size_t func_len{2};
private:
size_t value_size; // Number of bits
const std::vector<std::string>& operators; // List of operators
std::vector<uint64_t> params; // Current params
bool finished; // Indicates if all combinations have been generated
std::unordered_map<std::string, ParamLimits> operators_parameters; // Parameters for each operator

// Advance to the next combination
bool advance() {
for (int i = operators.size() - 1; i >= 0; --i) {
std::string op = operators[i];
ParamLimits& limits = operators_parameters[op];

if (params[i] + limits.step <= limits.max) {
params[i] += limits.step;

for (size_t j = i + 1; j < operators.size(); ++j) {
params[j] = operators_parameters[operators[j]].min;
}
return true;
}
}

return false; // No more combinations
}
};


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

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

size_t const value_size {argparser.createParam<size_t>(8, "num-bits", "Number of bits for the hash function", 'b', "Hash function").value()};

size_t const func_len {argparser.createParam<size_t>(2, "num-ops", "Number of operators for the hash function", 'n', "Hash function").value()};


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

// // 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);
// }
// }
// List of operator classes
std::vector<std::string> operators{"XorLeftShift", "XorRightShift", "AddShift", "Multiply"};

std::vector<std::string> best_operators;
std::vector<uint64_t> best_parameters;
double best_score = 10000000;

CombinationIterator c_iter(operators, func_len);
for (std::vector<std::string> operators : c_iter)
{
// Compute all the operator combinations
ParamEnumerator p_iter(value_size, operators);
for (std::vector<uint64_t> parameters : p_iter)
{
double score = test_hash_function(value_size, operators, parameters);
if (score < best_score)
{
best_score = score;
best_operators = operators;
best_parameters = parameters;

std::stringstream ss;
ss << best_score << " ";
for (size_t i = 0; i < best_operators.size(); ++i)
{
ss << best_operators[i] << " " << best_parameters[i] << " ";
}

CLUTCHLOG(note, "New best score: " << ss.str());

}
}
}

return 0;
}
Expand Down
24 changes: 24 additions & 0 deletions data/hash_loading.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Number of hash function in the file
5

# --- Examples ---

# Description of a hash function. 1 per line formated as follow
# num_bits num_operators operator1 param1 [... operatorN paramN]
16 3 XSR 3 MUL 47 XSR 2
16 3 XSR 7 MUL 61053 XSR 9

# Empty and #-started lines are skipped


# --- 8bits 3 Operators ---

# Bad score 0.662474
8 3 XSL 2 XSR 3 ASL 1
# 0.304274
8 3 XSR 4 MUL 43 XSR 4
# Best possible score 0.28054
8 3 MUL 43 XSR 7 MUL 87


# --- 8bits 4 Operators ---
Loading

0 comments on commit b1d057e

Please sign in to comment.