I've played around with HashCat and Kali Linux a bit, and honestly, they look nice—but they're slower than NoMachine WIF Hunter when it comes to Base58 decoding on the CPU. I've never, ever seen faster decoding and checksumming of WIFs—I'm getting 25MKeys/s here. And yes, it uses nested loops—testing all combinations—just like HashCat does. But NO random mode here. But who cares how many prefixes there are? What you really need is a pure random version here. Checksum-ignored Base58 decoding won’t work well here—you’ll just end up with overhead from false positives or false negatives.

You’d like everything ready to use without lifting a finger to do anything yourself.
Like most people, of course.
Here’s an example of code that works in the Base58 case—randomly and fast enough:
class Xoshiro256plus {
public:
Xoshiro256plus(uint64_t seed = 0) {
state[0] = splitmix64(seed);
for (int i = 1; i < 4; ++i) {
state[i] = splitmix64(state[i - 1]);
}
}
inline uint64_t next() __attribute__((hot)) {
const uint64_t s0 = state[0];
const uint64_t s1 = state[1];
const uint64_t s2 = state[2];
const uint64_t s3 = state[3];
const uint64_t result = s0 + s3;
const uint64_t t = s1 << 17;
state[2] = s2 ^ s0;
state[3] = s3 ^ s1;
state[1] = s1 ^ state[2];
state[0] = s0 ^ state[3];
state[2] ^= t;
state[3] = rotl(state[3], 45);
return result;
}
private:
inline uint64_t splitmix64(uint64_t x) __attribute__((always_inline)) {
uint64_t z = (x += 0x9e3779b97f4a7c15);
z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
return z ^ (z >> 31);
}
inline uint64_t rotl(const uint64_t x, int k) __attribute__((always_inline)) {
return (x << k) | (x >> (64 - k));
}
alignas(32) std::array<uint64_t, 4> state;
};
uint64_t get_random_index(Xoshiro256plus& rng) {
uint64_t max = UINT64_MAX - (UINT64_MAX % 58);
while (true) {
uint64_t rand_val = rng.next();
if (rand_val < max) {
return rand_val % 58;
}
}
}
It won’t work without splitmix64…

But the rest of the code—you’ll have to figure that out yourself.
