int64 pow_mod(int64 x, int64 y, int64 mod) { int64 ret = 1, val = x; for (; y > 0; y >>= 1) { if ((y & 1) == 1) ret = multiply_mod(ret, val, mod); val = multiply_mod(val, val, mod); } return ret; }
// Public library function. Returns NULL if successful, a string starting with "I/O error: " // if an I/O error occurred (please see perror()), or a string if some other error occurred. const char *modify_file_crc32(const char *path, uint64_t offset, uint32_t newcrc, bool printstatus) { FILE *f = fopen(path, "r+b"); if (f == NULL) return "I/O error: fopen"; // Read entire file and calculate original CRC-32 value. // Note: We can't use fseek(f, 0, SEEK_END) + ftell(f) to determine the length of the file, due to undefined behavior. // To be portable, we also avoid using POSIX fseeko()+ftello() or Windows GetFileSizeEx()/_filelength(). uint64_t length; uint32_t crc = get_crc32_and_length(f, &length); if (offset > UINT64_MAX - 4 || offset + 4 > length) { fclose(f); return "Error: Byte offset plus 4 exceeds file length"; } if (printstatus) fprintf(stdout, "Original CRC-32: %08" PRIX32 "\n", reverse_bits(crc)); // Compute the change to make uint32_t delta = crc ^ newcrc; delta = (uint32_t)multiply_mod(reciprocal_mod(pow_mod(2, (length - offset) * 8)), delta); // Patch 4 bytes in the file fseek64(f, offset); for (int i = 0; i < 4; i++) { int b = fgetc(f); if (b == EOF) { fclose(f); return "I/O error: fgetc"; } b ^= (int)((reverse_bits(delta) >> (i * 8)) & 0xFF); if (fseek(f, -1, SEEK_CUR) != 0) { fclose(f); return "I/O error: fseek"; } if (fputc(b, f) == EOF) { fclose(f); return "I/O error: fputc"; } if (fflush(f) == EOF) { fclose(f); return "I/O error: fflush"; } } if (printstatus) fprintf(stdout, "Computed and wrote patch\n"); // Recheck entire file bool match = get_crc32_and_length(f, &length) == newcrc; fclose(f); if (match) { if (printstatus) fprintf(stdout, "New CRC-32 successfully verified\n"); return NULL; // Success } else return "Assertion error: Failed to update CRC-32 to desired value"; }
int64 pollard_rho(int64 n, int64 c) { int64 x = rand() % (n - 1) + 1, y = x; for (int head = 1, tail = 2; true; ) { x = multiply_mod(x, x, n); if ((x += c) >= n) x -= n; if (x == y) return n; int64 d = gcd(my_abs(x - y), n); if (d > 1 && d < n) return d; if ((++head) == tail) { y = x; tail <<= 1; } } }