nerdletter/cipher/padgen.py

34 lines
1.3 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
"""Generate a one-time pad of uppercase letters from /dev/urandom."""
import sys
def generate_daybook(weeks: int = 52):
for week in range(1, weeks + 1):
with open(f"daybook_week_{week:02d}.txt", "w") as f:
f.write(f"WEEK {week:02d}\n\n")
f.write(format_pad(generate_pad(500)))
def generate_pad(num_letters: int) -> str:
"""Read raw bytes from /dev/urandom and map them uniformly to A-Z."""
letters = []
with open("/dev/urandom", "rb") as f:
while len(letters) < num_letters:
b = f.read(1)[0]
# Reject bytes >= 234 to avoid modulo bias.
# 234 = 9 * 26, so bytes 0..233 map uniformly to 0..25.
if b < 234:
letters.append(chr((b % 26) + 65))
return "".join(letters)
def format_pad(text: str, group_size: int = 5, groups_per_line: int = 10) -> str:
"""Format as 5-letter groups, 10 groups per line — classic OTP layout."""
groups = [text[i:i + group_size] for i in range(0, len(text), group_size)]
lines = [" ".join(groups[i:i + groups_per_line])
for i in range(0, len(groups), groups_per_line)]
return "\n".join(lines)
if __name__ == "__main__":
n = int(sys.argv[1]) if len(sys.argv) > 1 else 500
print(format_pad(generate_pad(n)))