Skip to content

Instantly share code, notes, and snippets.

@ziemek99
Last active October 30, 2024 14:03
Show Gist options
  • Save ziemek99/27a27dd0737694f157baffb7ff89e680 to your computer and use it in GitHub Desktop.
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.
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