128 lines
3.3 KiB
C++
128 lines
3.3 KiB
C++
#include "./PrecomputedPuzzles.h"
|
|
#include "..//Configuration.h"
|
|
#include <tomcrypt.h>
|
|
|
|
using namespace std;
|
|
using namespace ts::server::udp;
|
|
|
|
Puzzle::Puzzle() {
|
|
mp_init_multi(&this->x, &this->n, &this->result, nullptr);
|
|
}
|
|
|
|
Puzzle::~Puzzle() {
|
|
mp_clear_multi(&this->x, &this->n, &this->result, nullptr);
|
|
}
|
|
|
|
PuzzleManager::PuzzleManager() = default;
|
|
PuzzleManager::~PuzzleManager() = default;
|
|
|
|
size_t PuzzleManager::precomputed_puzzle_count() {
|
|
std::lock_guard lock{this->cache_mutex};
|
|
return this->cached_puzzles.size();
|
|
}
|
|
|
|
bool PuzzleManager::precompute_puzzles(size_t amount) {
|
|
std::random_device rd{};
|
|
std::mt19937 mt{rd()};
|
|
|
|
amount = 5;
|
|
while(this->precomputed_puzzle_count() < amount) {
|
|
this->generate_puzzle(mt);
|
|
}
|
|
|
|
return this->precomputed_puzzle_count() > 0;
|
|
}
|
|
|
|
std::shared_ptr<Puzzle> PuzzleManager::next_puzzle() {
|
|
{
|
|
std::lock_guard lock{this->cache_mutex};
|
|
auto it = this->cached_puzzles.begin() + (this->cache_index++ % this->cached_puzzles.size());
|
|
if((*it)->fail_count > 2) {
|
|
this->cached_puzzles.erase(it);
|
|
} else {
|
|
return *it;
|
|
}
|
|
}
|
|
|
|
std::random_device rd{};
|
|
std::mt19937 mt{rd()};
|
|
this->generate_puzzle(mt);
|
|
return this->next_puzzle();
|
|
}
|
|
|
|
inline void random_number(std::mt19937& generator, mp_int *result, int length){
|
|
std::uniform_int_distribution<uint8_t> dist{};
|
|
|
|
uint8_t buffer[length];
|
|
for(auto& byte : buffer) {
|
|
byte = dist(generator);
|
|
}
|
|
|
|
mp_zero(result);
|
|
mp_read_unsigned_bin(result, buffer, length);
|
|
}
|
|
|
|
inline bool solve_puzzle(Puzzle *puzzle) {
|
|
mp_int exp{};
|
|
mp_init(&exp);
|
|
mp_2expt(&exp, puzzle->level);
|
|
|
|
if (mp_exptmod(&puzzle->x, &exp, &puzzle->n, &puzzle->result) != CRYPT_OK) { //Sometimes it fails (unknown why :D)
|
|
mp_clear(&exp);
|
|
return false;
|
|
}
|
|
|
|
mp_clear(&exp);
|
|
return true;
|
|
}
|
|
|
|
inline bool write_bin_data(mp_int& data, uint8_t* result, size_t length) {
|
|
ulong n{length};
|
|
if(auto err = mp_to_unsigned_bin_n(&data, result, &n); err) {
|
|
return false;
|
|
}
|
|
|
|
if(n != length) {
|
|
auto off = length - n;
|
|
memmove(result + off, result, n);
|
|
memset(result, 0, off);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void PuzzleManager::generate_puzzle(std::mt19937& random_generator) {
|
|
auto puzzle = std::make_shared<Puzzle>();
|
|
puzzle->level = ts::config::voice::RsaPuzzleLevel;
|
|
|
|
while(true) {
|
|
random_number(random_generator, &puzzle->x, 64);
|
|
random_number(random_generator, &puzzle->n, 64);
|
|
|
|
if(!solve_puzzle(&*puzzle)) {
|
|
continue;
|
|
}
|
|
|
|
auto valid_x = mp_unsigned_bin_size(&puzzle->x) <= 64;
|
|
auto valid_n = mp_unsigned_bin_size(&puzzle->n) <= 64;
|
|
auto valid_result = mp_unsigned_bin_size(&puzzle->result) <= 64;
|
|
if(!valid_n || !valid_x || !valid_result) {
|
|
continue;
|
|
}
|
|
|
|
if(!write_bin_data(puzzle->x, puzzle->data_x, 64)) {
|
|
continue;
|
|
}
|
|
|
|
if(!write_bin_data(puzzle->n, puzzle->data_n, 64)) {
|
|
continue;
|
|
}
|
|
|
|
if(!write_bin_data(puzzle->result, puzzle->data_result, 64)) {
|
|
continue;
|
|
}
|
|
|
|
/* everything seems to be good */
|
|
break;
|
|
}
|
|
this->cached_puzzles.push_back(std::move(puzzle));
|
|
} |