Code cleanup™️
This commit is contained in:
parent
ad076a8150
commit
5742d3604c
182
src/main.cpp
182
src/main.cpp
|
@ -2,35 +2,15 @@
|
|||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/thread_pool.hpp>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
|
||||
#include "xoshiro.hpp"
|
||||
#include <thread>
|
||||
|
||||
namespace asio = boost::asio;
|
||||
// nvm doesnt work lol :)
|
||||
// using asio::experimental::concurrent_channel;
|
||||
|
||||
template <class TRandomAlgo>
|
||||
std::string RandomString(std::uint32_t length, TRandomAlgo& rng) {
|
||||
std::string s;
|
||||
s.resize(length);
|
||||
while(true) {
|
||||
auto res = rng();
|
||||
auto acc = 0u;
|
||||
|
||||
// I love bit hacks!!!
|
||||
for(std::size_t i = 0; i < sizeof(res); ++i) {
|
||||
std::uint8_t c = (res >> acc);
|
||||
if(islower(c)) {
|
||||
if(length-- <= 0)
|
||||
return s;
|
||||
s.push_back(c);
|
||||
}
|
||||
acc += CHAR_BIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
constexpr static auto MAX_CODE_LENGTH = 8;
|
||||
constexpr static auto THREAD_COUNT = 26; // this is a-z
|
||||
|
||||
/// This is a constexpr-safe zero-allocation version of the algorithm
|
||||
/// the "Scramble" ConsoleScript hash algorithm.
|
||||
constexpr std::uint32_t SwsfScramble(std::string_view code) {
|
||||
std::uint32_t tally {};
|
||||
|
||||
|
@ -47,13 +27,26 @@ constexpr std::uint32_t SwsfScramble(std::string_view code) {
|
|||
return tally;
|
||||
}
|
||||
|
||||
// These is not atomic since no other threads update it
|
||||
// there is no real point to making it atomic, other than
|
||||
//
|
||||
// maybe preventing some false sharing or other perf problem
|
||||
// ... but I don't think that matters, lol
|
||||
std::uint32_t code_hash = 0x2c73af55;
|
||||
std::uint32_t code_length = 8;
|
||||
struct FputcIterator {
|
||||
using iterator_category = std::output_iterator_tag;
|
||||
using value_type = void;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = void;
|
||||
using reference = void;
|
||||
|
||||
FputcIterator(std::FILE* file) : file(file) {}
|
||||
FputcIterator& operator*() { return *this; }
|
||||
FputcIterator& operator++() { return *this; }
|
||||
FputcIterator& operator++(int) { return *this; }
|
||||
|
||||
FputcIterator& operator=(const char& val) {
|
||||
fputc(val, file);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
std::FILE* file;
|
||||
};
|
||||
|
||||
bool NextCode(std::string& buffer, size_t start) {
|
||||
size_t len = buffer.length();
|
||||
|
@ -87,10 +80,15 @@ namespace {
|
|||
return "\r" + (m < 0 ? "\33[" + std::to_string(-m) + 'A' : std::string(m, '\n'));
|
||||
}
|
||||
|
||||
std::string_view ResetLine() {
|
||||
return "\33[2J";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
struct ThreadDisplayData {
|
||||
ThreadDisplayData() { codeString.resize(8); }
|
||||
/// This class implements the display of progress
|
||||
struct ThreadInfoData {
|
||||
ThreadInfoData() { codeString.resize(MAX_CODE_LENGTH); }
|
||||
|
||||
std::uint32_t threadIndex;
|
||||
std::string codeString;
|
||||
|
@ -98,104 +96,118 @@ struct ThreadDisplayData {
|
|||
bool done = false;
|
||||
|
||||
void DisplayProgress() {
|
||||
struct FputcIterator {
|
||||
using iterator_category = std::output_iterator_tag;
|
||||
using value_type = void;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = void;
|
||||
using reference = void;
|
||||
|
||||
FputcIterator(std::FILE* file) : file(file) {}
|
||||
FputcIterator& operator*() { return *this; }
|
||||
FputcIterator& operator++() { return *this; }
|
||||
FputcIterator& operator++(int) { return *this; }
|
||||
|
||||
FputcIterator& operator=(const char& val) {
|
||||
fputc(val, file);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
std::FILE* file;
|
||||
};
|
||||
|
||||
if(!done)
|
||||
std::format_to(FputcIterator(stdout), "{}Thread {:2}: Trying code {}{} {}({:08x}){}", Line(threadIndex), threadIndex, Color(172),
|
||||
codeString, Color(166), codeHash, Reset());
|
||||
else {
|
||||
std::format_to(FputcIterator(stdout), "{}Thread {:2}: {}Finished!{}", Line(threadIndex), threadIndex, Color(172), Reset());
|
||||
std::format_to(FputcIterator(stdout), "{}{}Thread {:2}: {}Finished!{}", Line(threadIndex), ResetLine(), threadIndex, Color(172), Reset());
|
||||
}
|
||||
std::fflush(stdout);
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<ThreadDisplayData> data(26);
|
||||
std::vector<ThreadInfoData> infoData(THREAD_COUNT);
|
||||
|
||||
struct BruteThreadState {
|
||||
BruteThreadState(unsigned tid) : threadIndex(tid) {}
|
||||
/// This class actually implements the brunt of the logic
|
||||
struct BruteforceWorker {
|
||||
|
||||
void BruteForce(char prefix) {
|
||||
// for(std::uint32_t i = 8; i <= code_length; ++i) {
|
||||
test_buffer.resize(code_length, 'a');
|
||||
/// Options for the worker.
|
||||
struct Options {
|
||||
/// The target hash to find matches for.
|
||||
std::uint32_t targetHash;
|
||||
|
||||
/// If `startLength` should be treated as the code length.
|
||||
bool exact;
|
||||
|
||||
std::uint32_t startLength;
|
||||
std::uint32_t endLength;
|
||||
};
|
||||
|
||||
constexpr BruteforceWorker(unsigned tid, const Options& options) : options(options), threadIndex(tid) {}
|
||||
|
||||
/// Public-facing driver function - the thread pool runs this.
|
||||
void Bruteforce(char prefix) {
|
||||
if(options.exact) {
|
||||
BruteforceForLength(prefix, options.startLength);
|
||||
} else {
|
||||
for(std::uint32_t i = options.startLength; i <= options.endLength; ++i)
|
||||
BruteforceForLength(prefix, i);
|
||||
}
|
||||
|
||||
DisplayData().done = true;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void BruteforceForLength(char prefix, std::uint32_t length) {
|
||||
DisplayData().codeString.resize(length);
|
||||
test_buffer.resize(length, 'a');
|
||||
test_buffer[0] = prefix;
|
||||
|
||||
// test all possible combinations
|
||||
while(true) {
|
||||
// std::string test_buffer = RandomString(code_length, rng);
|
||||
hash = SwsfScramble(test_buffer);
|
||||
if(hash == code_hash) {
|
||||
std::cerr << std::format("match: {} ({:08x})\n", test_buffer, hash);
|
||||
}
|
||||
|
||||
memcpy(data[threadIndex].codeString.data(), test_buffer.data(), test_buffer.length());
|
||||
data[threadIndex].codeHash = hash;
|
||||
// There was a match!
|
||||
if(hash == options.targetHash)
|
||||
std::format_to(FputcIterator(stderr), "match: {} ({:08x})\n", test_buffer, hash);
|
||||
|
||||
// DisplayProgress(test_buffer, hash);
|
||||
CopyDisplayData();
|
||||
|
||||
if(!NextCode(test_buffer, 1))
|
||||
break;
|
||||
}
|
||||
//}
|
||||
|
||||
data[threadIndex].done = true;
|
||||
}
|
||||
|
||||
std::string test_buffer;
|
||||
std::uint32_t hash;
|
||||
void CopyDisplayData() {
|
||||
memcpy(DisplayData().codeString.data(), test_buffer.data(), test_buffer.length());
|
||||
DisplayData().codeHash = hash;
|
||||
}
|
||||
|
||||
constexpr ThreadInfoData& DisplayData() { return infoData[threadIndex]; }
|
||||
|
||||
Options options;
|
||||
|
||||
unsigned threadIndex;
|
||||
std::random_device rd;
|
||||
// swbf::Xoshiro256ss rng{rd};
|
||||
std::string test_buffer;
|
||||
std::uint32_t hash;
|
||||
};
|
||||
|
||||
int main() {
|
||||
asio::io_context ioc;
|
||||
|
||||
asio::thread_pool pool(27);
|
||||
asio::thread_pool pool(THREAD_COUNT);
|
||||
|
||||
auto threadIndex = 0u;
|
||||
|
||||
BruteforceWorker::Options options {
|
||||
.targetHash = 0x2c73af55,
|
||||
.exact = true,
|
||||
.startLength = 8
|
||||
};
|
||||
|
||||
// post worker threads to run onto the thread pool & wait for them to complete
|
||||
for(int i = 0; i < 26; ++i)
|
||||
asio::post(pool, [&, i, tid = threadIndex++]() {
|
||||
BruteThreadState state(tid);
|
||||
data[tid].threadIndex = tid;
|
||||
state.BruteForce('a' + i);
|
||||
for(int i = 0; i < THREAD_COUNT; ++i)
|
||||
asio::post(pool, [&, tid = threadIndex++]() {
|
||||
BruteforceWorker state(tid, options);
|
||||
infoData[tid].threadIndex = tid;
|
||||
state.Bruteforce('a' + tid);
|
||||
});
|
||||
|
||||
bool done = false;
|
||||
|
||||
while(!done) {
|
||||
int doneIndex = 0;
|
||||
for(auto& d : data) {
|
||||
for(auto& d : infoData) {
|
||||
if(d.done)
|
||||
doneIndex++;
|
||||
d.DisplayProgress();
|
||||
}
|
||||
|
||||
if(doneIndex == 26) {
|
||||
if(doneIndex == THREAD_COUNT)
|
||||
done = true;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(66));
|
||||
}
|
||||
|
||||
pool.join(); // just in case!
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <climits> // CHAR_BIT
|
||||
#include <random>
|
||||
|
||||
namespace swbf {
|
||||
namespace detail {
|
||||
template <class T>
|
||||
constexpr size_t BitSizeOf() {
|
||||
return sizeof(T) * CHAR_BIT;
|
||||
}
|
||||
|
||||
constexpr std::uint64_t splitmix64(std::uint64_t x) {
|
||||
std::uint64_t z = (x += 0x9e3779b97f4a7c15uLL);
|
||||
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9uLL;
|
||||
z = (z ^ (z >> 27)) * 0x94d049bb133111ebuLL;
|
||||
return z ^ (z >> 31);
|
||||
}
|
||||
|
||||
constexpr std::uint64_t rotl(std::uint64_t x, int k) {
|
||||
return (x << k) | (x >> (BitSizeOf<std::uint64_t>() - k));
|
||||
}
|
||||
|
||||
/**
|
||||
* Xoshiro256** as a C++ RandomNumberEngine,
|
||||
* which can be used in C++ random algorithms.
|
||||
*/
|
||||
struct Xoshiro256ss {
|
||||
using result_type = std::uint64_t;
|
||||
|
||||
std::uint64_t s[4] {};
|
||||
|
||||
constexpr explicit Xoshiro256ss() : Xoshiro256ss(0) {}
|
||||
|
||||
constexpr explicit Xoshiro256ss(std::uint64_t seed) {
|
||||
s[0] = splitmix64(seed);
|
||||
s[1] = splitmix64(seed);
|
||||
s[2] = splitmix64(seed);
|
||||
s[3] = splitmix64(seed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for seeding from a `std::random_device`.
|
||||
*
|
||||
* \param[in] rd Random device to seed this engine with.
|
||||
*/
|
||||
constexpr explicit Xoshiro256ss(std::random_device& rd) {
|
||||
// Get 64 bits out of the random device.
|
||||
//
|
||||
// This lambda is quite literal, as it fetches
|
||||
// 2 iterations of the random engine, and
|
||||
// shifts + OR's them into a 64bit value.
|
||||
auto get_u64 = [&rd] {
|
||||
std::uint64_t the_thing = rd();
|
||||
return (the_thing << 32) | rd();
|
||||
};
|
||||
|
||||
// seed with 256 bits of entropy from the random device + splitmix64
|
||||
// to ensure we seed it well, as per recommendation.
|
||||
s[0] = splitmix64(get_u64());
|
||||
s[1] = splitmix64(get_u64());
|
||||
s[2] = splitmix64(get_u64());
|
||||
s[3] = splitmix64(get_u64());
|
||||
}
|
||||
|
||||
static constexpr result_type min() { return 0; }
|
||||
|
||||
static constexpr result_type max() { return std::uint64_t(-1); }
|
||||
|
||||
constexpr result_type operator()() {
|
||||
result_type result = rotl(s[1] * 5, 7) * 9;
|
||||
result_type t = s[1] << 17;
|
||||
s[2] ^= s[0];
|
||||
s[3] ^= s[1];
|
||||
s[1] ^= s[2];
|
||||
s[0] ^= s[3];
|
||||
s[2] ^= t;
|
||||
s[3] = rotl(s[3], 45);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
using detail::Xoshiro256ss;
|
||||
} // namespace swbf
|
Loading…
Reference in New Issue