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/post.hpp>
|
||||||
#include <boost/asio/thread_pool.hpp>
|
#include <boost/asio/thread_pool.hpp>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <iostream>
|
#include <thread>
|
||||||
|
|
||||||
#include "xoshiro.hpp"
|
|
||||||
|
|
||||||
namespace asio = boost::asio;
|
namespace asio = boost::asio;
|
||||||
// nvm doesnt work lol :)
|
|
||||||
// using asio::experimental::concurrent_channel;
|
|
||||||
|
|
||||||
template <class TRandomAlgo>
|
constexpr static auto MAX_CODE_LENGTH = 8;
|
||||||
std::string RandomString(std::uint32_t length, TRandomAlgo& rng) {
|
constexpr static auto THREAD_COUNT = 26; // this is a-z
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// 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) {
|
constexpr std::uint32_t SwsfScramble(std::string_view code) {
|
||||||
std::uint32_t tally {};
|
std::uint32_t tally {};
|
||||||
|
|
||||||
|
@ -47,13 +27,26 @@ constexpr std::uint32_t SwsfScramble(std::string_view code) {
|
||||||
return tally;
|
return tally;
|
||||||
}
|
}
|
||||||
|
|
||||||
// These is not atomic since no other threads update it
|
struct FputcIterator {
|
||||||
// there is no real point to making it atomic, other than
|
using iterator_category = std::output_iterator_tag;
|
||||||
//
|
using value_type = void;
|
||||||
// maybe preventing some false sharing or other perf problem
|
using difference_type = std::ptrdiff_t;
|
||||||
// ... but I don't think that matters, lol
|
using pointer = void;
|
||||||
std::uint32_t code_hash = 0x2c73af55;
|
using reference = void;
|
||||||
std::uint32_t code_length = 8;
|
|
||||||
|
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) {
|
bool NextCode(std::string& buffer, size_t start) {
|
||||||
size_t len = buffer.length();
|
size_t len = buffer.length();
|
||||||
|
@ -87,10 +80,15 @@ namespace {
|
||||||
return "\r" + (m < 0 ? "\33[" + std::to_string(-m) + 'A' : std::string(m, '\n'));
|
return "\r" + (m < 0 ? "\33[" + std::to_string(-m) + 'A' : std::string(m, '\n'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string_view ResetLine() {
|
||||||
|
return "\33[2J";
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
struct ThreadDisplayData {
|
/// This class implements the display of progress
|
||||||
ThreadDisplayData() { codeString.resize(8); }
|
struct ThreadInfoData {
|
||||||
|
ThreadInfoData() { codeString.resize(MAX_CODE_LENGTH); }
|
||||||
|
|
||||||
std::uint32_t threadIndex;
|
std::uint32_t threadIndex;
|
||||||
std::string codeString;
|
std::string codeString;
|
||||||
|
@ -98,104 +96,118 @@ struct ThreadDisplayData {
|
||||||
bool done = false;
|
bool done = false;
|
||||||
|
|
||||||
void DisplayProgress() {
|
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)
|
if(!done)
|
||||||
std::format_to(FputcIterator(stdout), "{}Thread {:2}: Trying code {}{} {}({:08x}){}", Line(threadIndex), threadIndex, Color(172),
|
std::format_to(FputcIterator(stdout), "{}Thread {:2}: Trying code {}{} {}({:08x}){}", Line(threadIndex), threadIndex, Color(172),
|
||||||
codeString, Color(166), codeHash, Reset());
|
codeString, Color(166), codeHash, Reset());
|
||||||
else {
|
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::fflush(stdout);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<ThreadDisplayData> data(26);
|
std::vector<ThreadInfoData> infoData(THREAD_COUNT);
|
||||||
|
|
||||||
struct BruteThreadState {
|
/// This class actually implements the brunt of the logic
|
||||||
BruteThreadState(unsigned tid) : threadIndex(tid) {}
|
struct BruteforceWorker {
|
||||||
|
|
||||||
void BruteForce(char prefix) {
|
/// Options for the worker.
|
||||||
// for(std::uint32_t i = 8; i <= code_length; ++i) {
|
struct Options {
|
||||||
test_buffer.resize(code_length, 'a');
|
/// 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_buffer[0] = prefix;
|
||||||
|
|
||||||
// test all possible combinations
|
// test all possible combinations
|
||||||
while(true) {
|
while(true) {
|
||||||
// std::string test_buffer = RandomString(code_length, rng);
|
|
||||||
hash = SwsfScramble(test_buffer);
|
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());
|
// There was a match!
|
||||||
data[threadIndex].codeHash = hash;
|
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))
|
if(!NextCode(test_buffer, 1))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//}
|
|
||||||
|
|
||||||
data[threadIndex].done = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string test_buffer;
|
void CopyDisplayData() {
|
||||||
std::uint32_t hash;
|
memcpy(DisplayData().codeString.data(), test_buffer.data(), test_buffer.length());
|
||||||
|
DisplayData().codeHash = hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ThreadInfoData& DisplayData() { return infoData[threadIndex]; }
|
||||||
|
|
||||||
|
Options options;
|
||||||
|
|
||||||
unsigned threadIndex;
|
unsigned threadIndex;
|
||||||
std::random_device rd;
|
std::string test_buffer;
|
||||||
// swbf::Xoshiro256ss rng{rd};
|
std::uint32_t hash;
|
||||||
};
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
asio::io_context ioc;
|
asio::io_context ioc;
|
||||||
|
|
||||||
asio::thread_pool pool(27);
|
asio::thread_pool pool(THREAD_COUNT);
|
||||||
|
|
||||||
auto threadIndex = 0u;
|
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
|
// post worker threads to run onto the thread pool & wait for them to complete
|
||||||
for(int i = 0; i < 26; ++i)
|
for(int i = 0; i < THREAD_COUNT; ++i)
|
||||||
asio::post(pool, [&, i, tid = threadIndex++]() {
|
asio::post(pool, [&, tid = threadIndex++]() {
|
||||||
BruteThreadState state(tid);
|
BruteforceWorker state(tid, options);
|
||||||
data[tid].threadIndex = tid;
|
infoData[tid].threadIndex = tid;
|
||||||
state.BruteForce('a' + i);
|
state.Bruteforce('a' + tid);
|
||||||
});
|
});
|
||||||
|
|
||||||
bool done = false;
|
bool done = false;
|
||||||
|
|
||||||
while(!done) {
|
while(!done) {
|
||||||
int doneIndex = 0;
|
int doneIndex = 0;
|
||||||
for(auto& d : data) {
|
for(auto& d : infoData) {
|
||||||
if(d.done)
|
if(d.done)
|
||||||
doneIndex++;
|
doneIndex++;
|
||||||
d.DisplayProgress();
|
d.DisplayProgress();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(doneIndex == 26) {
|
if(doneIndex == THREAD_COUNT)
|
||||||
done = true;
|
done = true;
|
||||||
}
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(66));
|
||||||
}
|
}
|
||||||
|
|
||||||
pool.join(); // just in case!
|
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