Posting the code, since you expressed interest in it. Here we have the "encoder" which encodes a 6-bit integer (between 1 and 63) into the full serial. Note that we skip i=0 (and start at i=1) because the all-zero key is rejected by the routine, even though it is technically valid. There are no other valid keys.
I will spend some time thinking of a new challenge that is not so easy for UniSoft to solve next time
Code:
uint64_t generate(uint64_t x) {
uint64_t y = 0;
for (size_t i = 0; i < 64; ++i) {
uint64_t u = x & i;
uint64_t k = 0;
for (size_t j = 0; j < 6; ++j) {
k ^= (u >> j) & 1;
}
y |= k << i;
}
return y;
}
void print_keys() {
for (size_t i = 1; i < 64; ++i) {
uint64_t key = generate(i);
if (check(key)) {
std::cout << std::hex << key << std::endl;
} else {
std::cout << std::hex << key << " (BAD)" << std::endl;
}
}
}