Skip to content

Instantly share code, notes, and snippets.

@rgov
Last active April 24, 2019 00:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rgov/6d2ea6f324258674a97b664cba167681 to your computer and use it in GitHub Desktop.
Save rgov/6d2ea6f324258674a97b664cba167681 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
import random
# Here is our plaintext message
message = 'THISISATESTITISONLYATEST'
# Insert random spaces into the message
while len(message) < 72:
i = random.randrange(len(message))
message = message[:i] + ' ' + message[i:]
# Write the message across the six wheels
wheels = [[' '] * 72 for _ in range(6)]
for i, m in enumerate(message):
if m == ' ':
for w in wheels:
w[i] = random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZ')
else:
random.choice(wheels)[i] = m
# Generate a key
key = [ random.randrange(72) for _ in wheels ]
# Rotate the wheels the opposite direction
for w, k in zip(wheels, key):
w[:] = w[72 - k:] + w[:72 - k]
print('Scrambled wheels:')
for w in wheels:
print(' '.join(w))
print()
###########################
# Now let's try to brute force how wheel[i] aligns to wheel[0]
found_key = [ 0 for _ in wheels ]
for i, w in enumerate(wheels[1:]):
scores = []
for k in range(72):
collide = 0
gap = 0
letter = 0
for a, b in zip(wheels[0], w[k:] + w[:k]):
if a == ' ' and b == ' ':
gap += 1
elif a == ' ' or b == ' ':
letter += 1
else:
collide += 1
scores.append((k, collide, gap, letter))
# Select the rotation with the lowest letter count
best_score = min(scores, key=lambda score: score[3])
found_key[i + 1] = best_score[0]
# Rotate all the wheels according to our found key
for w, k in zip(wheels, found_key):
w[:] = w[k:] + w[:k]
print('Unscrambled wheels:')
for w in wheels:
print(' '.join(w))
print()
# We can now combine wheels and drop out any colliding characters:
decoded = ''
for i, chars in enumerate(zip(*wheels)):
if sum(1 for x in chars if x != ' ') > 1:
decoded += ' '
else:
decoded += next(x for x in chars if x != ' ')
# We don't know the orientation of the first wheel, but we can show all possible
# de-scramblings
print('Possible keys and plaintexts:')
for k in range(72):
out_key = [ (f + k) % 72 for f in found_key ]
print(out_key, ''.join(decoded[k:] + decoded[:k]).replace(' ', ''), end='')
print(' <--' if out_key == key else '')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment