[p[1] for p in wheel_spec])) != 26:
raise ValueError("Wheel specification does not contain 26 letters")
- def encipher(self, letter):
+ def encipher_letter(self, letter):
"""Enciphers a single letter, by advancing the wheel before looking up
the letter on the wheel.
>>> pe.set_position('f')
5
- >>> pe.encipher('k')
+ >>> pe.encipher_letter('k')
'h'
"""
self.advance()
return self.lookup(letter)
- decipher = encipher
+ decipher_letter = encipher_letter
def lookup(self, letter):
"""Look up what a letter enciphers to, without turning the wheel.
self.position = (self.position + 1) % 26
return self.position
- def encipher_message(self, message):
+ def encipher(self, message):
"""Enciphers a whole message.
>>> pe.set_position('f')
5
- >>> pe.encipher_message('helloworld')
+ >>> pe.encipher('helloworld')
'kjsglcjoqc'
>>> pe.set_position('f')
5
- >>> pe.encipher_message('kjsglcjoqc')
+ >>> pe.encipher('kjsglcjoqc')
'helloworld'
"""
transformed = ''
for l in message:
- transformed += self.encipher(l)
+ transformed += self.encipher_letter(l)
return transformed
- decipher_message = encipher_message
+ decipher = encipher
def set_position(self, position):
"""Sets the position of the wheel, by specifying the letter the arrow
return max(results, key=lambda k: k[1])
+def pocket_enigma_break_by_crib(message, wheel_spec, crib, crib_position):
+ """Break a pocket enigma using a crib (some plaintext that's expected to
+ be in a certain position). Returns a list of possible starting wheel
+ positions that could produce the crib.
+
+ >>> pocket_enigma_break_by_crib('kzpjlzmoga', 1, 'h', 0)
+ ['a', 'f', 'q']
+ >>> pocket_enigma_break_by_crib('kzpjlzmoga', 1, 'he', 0)
+ ['a']
+ >>> pocket_enigma_break_by_crib('kzpjlzmoga', 1, 'll', 2)
+ ['a']
+ >>> pocket_enigma_break_by_crib('kzpjlzmoga', 1, 'l', 2)
+ ['a']
+ >>> pocket_enigma_break_by_crib('kzpjlzmoga', 1, 'l', 3)
+ ['a', 'j', 'n']
+ >>> pocket_enigma_break_by_crib('aaaaa', 1, 'l', 3)
+ []
+ """
+ pe = PocketEnigma(wheel=wheel_spec)
+ possible_positions = []
+ for p in string.ascii_lowercase:
+ pe.set_position(p)
+ plaintext = pe.decipher(message)
+ if plaintext[crib_position:crib_position+len(crib)] == crib:
+ possible_positions += [p]
+ return possible_positions
+
+
def plot_frequency_histogram(freqs, sort_key=None):
x = range(len(freqs.keys()))
y = [freqs[l] for l in sorted(freqs.keys(), key=sort_key)]