Enable Javascript in your browser and then refresh this page, for a much enhanced experience.
recursive candidate keys generator solution in Clear category for Grille Cipher Attack by Sim0000
from typing import List
def find_grille(plaintext: str, cryptogram: str) -> List[str]:
"rotate matrix"
R = (7,15,23,31,39,47,55,63, 6,14,22,30,38,46,54,62, 5,13,21,29,37,45,53,61, 4,12,20,28,36,44,52,60, 3,11,19,27,35,43,51,59, 2,10,18,26,34,42,50,58, 1,9,17,25,33,41,49,57, 0,8,16,24,32,40,48,56)
R2 = tuple(R[R[i]] for i in range(64))
R3 = tuple(R[R[R[i]]] for i in range(64))
RR = {i: {i, R[i], R2[i], R3[i]} for i in range(64)}
def search(n, last, seen, hist):
"Generator that recursively generates candidate keys"
if n == 16:
yield hist
return
for i in cd[plaintext[n]]:
if i < last or i in seen: continue
if cryptogram[R[i]] not in plaintext[16:32]: continue
if plaintext[47 - n] != cryptogram[R2[i]]: continue
if cryptogram[R3[i]] not in plaintext[48:64]: continue
yield from search(n + 1, i + 1, seen | RR[i], hist + [i])
def check(k):
"Encrypt and check if the result matches the cryptogram"
key = []
for _ in range(4):
key.extend(k)
k = sorted(R[i] for i in k)
c = [''] * 64
for i, m in zip(key, plaintext): c[i] = m
return ''.join(c) == cryptogram
"Create a table of where each character in the plaintext moves to in the ciphertext"
cd = {}
for i, c in enumerate(cryptogram):
if c not in cd: cd[c] = []
cd[c].append(i)
"Checks all key candidates generated by search() for correct keys"
for k in search(0, 0, set(), []):
if check(k):
t = ['.'] * 64
for i in k: t[i] = 'X'
return [''.join(t[i:i+8]) for i in range(0, 64, 8)]
return [] # never reach
if __name__ == "__main__":
print("Example:")
print(
find_grille(
"quickbrownfoxjumpsoverthelazydogandjackdawslovesmysphinxofquartz",
"quicpsovkbroerthwnfoelazxjumydogmyspandjhinxackdofquawslartzoves",
)
)
# These "asserts" are used for self-checking and not for an auto-testing
assert find_grille(
"quickbrownfoxjumpsoverthelazydogandjackdawslovesmysphinxofquartz",
"quicpsovkbroerthwnfoelazxjumydogmyspandjhinxackdofquawslartzoves",
) == [
"XXXX....",
"XXXX....",
"XXXX....",
"XXXX....",
"........",
"........",
"........",
"........",
]
assert find_grille(
"weareallfromxanthcubesaidquicklyjustvisitingphazewewontbeforlong",
"wejhewucuaeswtbrveeoisantsalilbifdteifrqunooigrmplxcakhonnlagtyz",
) == [
"X...X...",
".X.....X",
"..X...X.",
"...X.X..",
"X.....X.",
"...X...X",
"..X.X...",
".X...X..",
]
assert find_grille(
"theideaofcognitivebiasinpsychologyworksinananalogouswayacognitiv",
"tgovgeubyhsiawseiinorkdepaswoasifcyncyaanaognconaginihlttoiivloo",
) == [
"X.......",
".X.....X",
"X.....XX",
".X..X...",
"XX......",
"..XXX...",
"..X....X",
"...X....",
]
print("Coding complete? Click 'Check' to earn cool rewards!")
Sept. 4, 2022
Comments: