Code cleanup™️

This commit is contained in:
Lily Tsuru 2023-08-22 03:30:40 -04:00
parent ad076a8150
commit 5742d3604c
2 changed files with 98 additions and 171 deletions

View File

@ -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!

View File

@ -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