Last active
October 30, 2024 14:03
-
-
Save ziemek99/27a27dd0737694f157baffb7ff89e680 to your computer and use it in GitHub Desktop.
Script that flips bits at random. You can spare first and last bits from the process.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from os import path | |
from random import randint | |
from sys import argv, stderr | |
def get_file_path(): | |
if not path.isfile(argv[1]): | |
raise FileNotFoundError | |
return argv[1] | |
def get_bitrot_count(): | |
bitrot_count = int(argv[2]) if len(argv) >= 3 else 1 | |
if bitrot_count < 0: | |
raise ValueError | |
return bitrot_count | |
def get_bitrot_excluded_bits(): | |
# The "end" variable isn't the end of the range, but the number of trailing bits to exclude from the range. | |
# E.g. if start = 3 and end = 2, the first 3 bits and last 2 bits will be excluded. | |
start = int(argv[3]) if len(argv) >= 4 else 0 | |
end = int(argv[4]) if len(argv) == 5 else 0 | |
if start < 0 or end < 0: | |
raise ValueError | |
return start, end | |
def bitrot(file_path, bitrot_count, start, end): | |
# Get the file size in bytes and convert it to bits | |
file_size_bits = path.getsize(file_path) * 8 | |
# Create a set of bit_to_flip values to avoid flipping the same bit multiple times | |
bits_flipped = set() | |
with open(file_path, 'r+b') as f: | |
for i in range(bitrot_count): | |
if i >= file_size_bits - (start + end): | |
print("No more bits to flip in this file.") | |
break | |
# Choose a random bit to flip within the allowed range | |
bit_to_flip = randint(start, file_size_bits - end - 1) | |
# If the bit has already been flipped, choose another bit | |
while bit_to_flip in bits_flipped: | |
bit_to_flip = randint(start, file_size_bits - end - 1) | |
# Add the bit to the set of flipped bits | |
bits_flipped.add(bit_to_flip) | |
# Determine the byte and bit position within that byte | |
byte_index = bit_to_flip // 8 | |
bit_index = bit_to_flip % 8 | |
# Read the byte at the byte_index | |
f.seek(byte_index) | |
byte = ord(f.read(1)) | |
# Flip the bit at bit_index | |
byte ^= (0b10000000 >> bit_index) | |
# Write the modified byte back to the file | |
f.seek(byte_index) | |
f.write(bytes([byte])) | |
print(f"Flipped bit {bit_to_flip}.") | |
def main(): | |
if len(argv) not in range(2, 6): | |
print("Usage: python bitrot.py file_path [bitrot_count [start [end]]]", file=stderr) | |
return | |
try: | |
file_path = get_file_path() | |
except FileNotFoundError: | |
print(f"File does not exist.", file=stderr) | |
return | |
try: | |
bitrot_count = get_bitrot_count() | |
start, end = get_bitrot_excluded_bits() | |
except ValueError: | |
print("Bitrot count and excluded bits must be non-negative integers.", file=stderr) | |
return | |
bitrot(file_path, bitrot_count, start, end) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment