X-Git-Url: https://git.njae.me.uk/?a=blobdiff_plain;f=cipher.py;h=e318aa46f8776fe24d9293e7d2b91def53d72663;hb=1bf8b88bd6c6f03de0736d4b7b278f6f76bc0180;hp=b1413691fb025aaf6a450bde0efa00d9163b5fee;hpb=7c5fd4061335669401bb298b5cec519b1f9afbc8;p=cipher-tools.git diff --git a/cipher.py b/cipher.py index b141369..e318aa4 100644 --- a/cipher.py +++ b/cipher.py @@ -13,6 +13,7 @@ import pprint ## Utility functions cat = ''.join wcat = ' '.join +lcat = '\n'.join def pos(letter): if letter in string.ascii_lowercase: @@ -381,7 +382,7 @@ def vigenere_encipher(message, keyword): >>> vigenere_encipher('hello', 'abc') 'hfnlp' """ - shifts = [ord(l) - ord('a') for l in sanitise(keyword)] + shifts = [pos(l) for l in sanitise(keyword)] pairs = zip(message, cycle(shifts)) return cat([caesar_encipher_letter(l, k) for l, k in pairs]) @@ -391,7 +392,7 @@ def vigenere_decipher(message, keyword): >>> vigenere_decipher('hfnlp', 'abc') 'hello' """ - shifts = [ord(l) - ord('a') for l in sanitise(keyword)] + shifts = [pos(l) for l in sanitise(keyword)] pairs = zip(message, cycle(shifts)) return cat([caesar_decipher_letter(l, k) for l, k in pairs]) @@ -903,12 +904,12 @@ def hill_encipher(matrix, message_letters, fillvalue='a'): padding = fillvalue[0] * (n - len(sanitised_message) % n) else: padding = '' - message = [ord(c) - ord('a') for c in sanitised_message + padding] + message = [pos(c) for c in sanitised_message + padding] message_chunks = [message[i:i+n] for i in range(0, len(message), n)] # message_chunks = chunks(message, len(matrix), fillvalue=None) enciphered_chunks = [((matrix * np.matrix(c).T).T).tolist()[0] for c in message_chunks] - return cat([chr(int(round(l)) % 26 + ord('a')) + return cat([unpos(round(l)) for l in sum(enciphered_chunks, [])]) def hill_decipher(matrix, message, fillvalue='a'): @@ -1136,6 +1137,32 @@ def bifid_decipher(message, keyword, wrap_alphabet=KeywordWrapAlphabet.from_a, return cat(r_grid[p] for p in pairs1) + +def autokey_encipher(message, keyword): + """Encipher with the autokey cipher + + >>> autokey_encipher('meetatthefountain', 'kilt') + 'wmpmmxxaeyhbryoca' + """ + shifts = [pos(l) for l in keyword + message] + pairs = zip(message, shifts) + return cat([caesar_encipher_letter(l, k) for l, k in pairs]) + +def autokey_decipher(ciphertext, keyword): + """Decipher with the autokey cipher + + >>> autokey_decipher('wmpmmxxaeyhbryoca', 'kilt') + 'meetatthefountain' + """ + plaintext = [] + keys = list(keyword) + for c in ciphertext: + plaintext_letter = caesar_decipher_letter(c, pos(keys[0])) + plaintext += [plaintext_letter] + keys = keys[1:] + [plaintext_letter] + return cat(plaintext) + + class PocketEnigma(object): """A pocket enigma machine The wheel is internally represented as a 26-element list self.wheel_map, @@ -1170,7 +1197,7 @@ class PocketEnigma(object): self.validate_wheel_spec(wheel) self.make_wheel_map(wheel) if position in string.ascii_lowercase: - self.position = ord(position) - ord('a') + self.position = pos(position) else: self.position = position @@ -1184,8 +1211,8 @@ class PocketEnigma(object): self.validate_wheel_spec(wheel_spec) self.wheel_map = [0] * 26 for p in wheel_spec: - self.wheel_map[ord(p[0]) - ord('a')] = ord(p[1]) - ord('a') - self.wheel_map[ord(p[1]) - ord('a')] = ord(p[0]) - ord('a') + self.wheel_map[pos(p[0])] = pos(p[1]) + self.wheel_map[pos(p[1])] = pos(p[0]) return self.wheel_map def validate_wheel_spec(self, wheel_spec): @@ -1240,10 +1267,9 @@ class PocketEnigma(object): '' """ if letter in string.ascii_lowercase: - return chr( - (self.wheel_map[(ord(letter) - ord('a') - self.position) % 26] + - self.position) % 26 + - ord('a')) + return unpos( + (self.wheel_map[(pos(letter) - self.position) % 26] + + self.position)) else: return '' @@ -1291,7 +1317,7 @@ class PocketEnigma(object): >>> pe.set_position('z') 25 """ - self.position = ord(position) - ord('a') + self.position = pos(position) return self.position