X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/4a29930e1b9db1332c93244365db1642fcfac1cd..61072f7be9d1ab83c459ec1eabc0f9503b57fac6:/mines.c diff --git a/mines.c b/mines.c index 388a7d5..6895b2e 100644 --- a/mines.c +++ b/mines.c @@ -1828,112 +1828,6 @@ static char *minegen(int w, int h, int n, int x, int y, int unique, return ret; } -/* - * The Mines game descriptions contain the location of every mine, - * and can therefore be used to cheat. - * - * It would be pointless to attempt to _prevent_ this form of - * cheating by encrypting the description, since Mines is - * open-source so anyone can find out the encryption key. However, - * I think it is worth doing a bit of gentle obfuscation to prevent - * _accidental_ spoilers: if you happened to note that the game ID - * starts with an F, for example, you might be unable to put the - * knowledge of those mines out of your mind while playing. So, - * just as discussions of film endings are rot13ed to avoid - * spoiling it for people who don't want to be told, we apply a - * keyless, reversible, but visually completely obfuscatory masking - * function to the mine bitmap. - */ -static void obfuscate_bitmap(unsigned char *bmp, int bits, int decode) -{ - int bytes, firsthalf, secondhalf; - struct step { - unsigned char *seedstart; - int seedlen; - unsigned char *targetstart; - int targetlen; - } steps[2]; - int i, j; - - /* - * My obfuscation algorithm is similar in concept to the OAEP - * encoding used in some forms of RSA. Here's a specification - * of it: - * - * + We have a `masking function' which constructs a stream of - * pseudorandom bytes from a seed of some number of input - * bytes. - * - * + We pad out our input bit stream to a whole number of - * bytes by adding up to 7 zero bits on the end. (In fact - * the bitmap passed as input to this function will already - * have had this done in practice.) - * - * + We divide the _byte_ stream exactly in half, rounding the - * half-way position _down_. So an 81-bit input string, for - * example, rounds up to 88 bits or 11 bytes, and then - * dividing by two gives 5 bytes in the first half and 6 in - * the second half. - * - * + We generate a mask from the second half of the bytes, and - * XOR it over the first half. - * - * + We generate a mask from the (encoded) first half of the - * bytes, and XOR it over the second half. Any null bits at - * the end which were added as padding are cleared back to - * zero even if this operation would have made them nonzero. - * - * To de-obfuscate, the steps are precisely the same except - * that the final two are reversed. - * - * Finally, our masking function. Given an input seed string of - * bytes, the output mask consists of concatenating the SHA-1 - * hashes of the seed string and successive decimal integers, - * starting from 0. - */ - - bytes = (bits + 7) / 8; - firsthalf = bytes / 2; - secondhalf = bytes - firsthalf; - - steps[decode ? 1 : 0].seedstart = bmp + firsthalf; - steps[decode ? 1 : 0].seedlen = secondhalf; - steps[decode ? 1 : 0].targetstart = bmp; - steps[decode ? 1 : 0].targetlen = firsthalf; - - steps[decode ? 0 : 1].seedstart = bmp; - steps[decode ? 0 : 1].seedlen = firsthalf; - steps[decode ? 0 : 1].targetstart = bmp + firsthalf; - steps[decode ? 0 : 1].targetlen = secondhalf; - - for (i = 0; i < 2; i++) { - SHA_State base, final; - unsigned char digest[20]; - char numberbuf[80]; - int digestpos = 20, counter = 0; - - SHA_Init(&base); - SHA_Bytes(&base, steps[i].seedstart, steps[i].seedlen); - - for (j = 0; j < steps[i].targetlen; j++) { - if (digestpos >= 20) { - sprintf(numberbuf, "%d", counter++); - final = base; - SHA_Bytes(&final, numberbuf, strlen(numberbuf)); - SHA_Final(&final, digest); - digestpos = 0; - } - steps[i].targetstart[j] ^= digest[digestpos++]; - } - - /* - * Mask off the pad bits in the final byte after both steps. - */ - if (bits % 8) - bmp[bits / 8] &= 0xFF & (0xFF00 >> (bits % 8)); - } -} - static char *describe_layout(char *grid, int area, int x, int y, int obfuscate) {