WHERE THE DREAM STARTS 3
Challenge
Upon your successful attacks of the precedent ciphers, Vigenere invited you to his cipher workshop. Friedman and Kasiski are there too.
A modification of a very nice classic.
Files given: encrypt.py, output.txt
Understanding the cipher
encrypt.py is Vigenere with an extra twist, a per-block drift term added on top of the usual repeating key:
def encrypt(pt: str, keyword: str) -> str:
m = len(keyword)
for i in range(len(pt)):
index = (pt[i] + key[i % m] + (i // m)) % 26
ct += ascii_lowercase[index]
Standard Vigenere shifts character i by key[i % m]. This "modification" adds i // m on top, so every time the keyword cycles fully, the effective shift for that whole cycle increases by one.
Solution
Decryption just inverts the forward formula, undoing both the repeating-key shift and the accumulating drift:
from string import ascii_lowercase
with open("output(6).txt", "r") as f:
ct_str = f.read().strip()
ct = [ascii_lowercase.index(c) for c in ct_str]
keyword = "dream"
m = len(keyword)
key = [ascii_lowercase.index(c) for c in keyword]
pt = []
for i in range(len(ct)):
pt_val = (ct[i] - key[i % m] - (i // m)) % 26
pt.append(ascii_lowercase[pt_val])
print("".join(pt))