Affine letter enciphering working
[cipher-tools.git] / cipher.py
1 import string
2 import collections
3
4 english_counts = collections.defaultdict(int)
5 with open('count_1l.txt', 'r') as f:
6 for line in f:
7 (letter, count) = line.split("\t")
8 english_counts[letter] = int(count)
9
10 def sanitise(text):
11 sanitised = [c.lower() for c in text if c in string.ascii_letters]
12 return ''.join(sanitised)
13
14 def letter_frequencies(message):
15 frequencies = collections.defaultdict(int)
16 for letter in sanitise(message):
17 frequencies[letter]+=1
18 return frequencies
19
20 def scale_freq(frequencies):
21 total= sum(frequencies.values())
22 scaled_frequencies = collections.defaultdict(int)
23 for letter in frequencies.keys():
24 scaled_frequencies[letter] = frequencies[letter] / total
25 return scaled_frequencies
26
27 def value_diff(frequencies1, frequencies2):
28 total= 0
29 for letter in frequencies1.keys():
30 total += abs(frequencies1[letter]-frequencies2[letter])
31 return total
32
33
34
35 def caesar_cipher_letter(letter, shift):
36 if letter in string.ascii_letters:
37 if letter in string.ascii_lowercase:
38 return chr((ord(letter) - ord('a') + shift) % 26 + ord('a'))
39 else:
40 new_letter = letter.lower()
41 yolo = chr((ord(new_letter) - ord('a') + shift) % 26 + ord('a'))
42 return yolo.upper()
43 else:
44 return letter
45
46 def caesar_decipher_letter(letter, shift):
47 return caesar_cipher_letter(letter, -shift)
48
49 def caesar_cipher_message(message, shift):
50 big_cipher = [caesar_cipher_letter(l, shift) for l in message]
51 return ''.join(big_cipher)
52
53 def caesar_decipher_message(message, shift):
54 return caesar_cipher_message(message, -shift)
55
56 def affine_cipher_letter(letter, multiplier, shift, one_based=True):
57 if letter in string.ascii_letters:
58 if letter in string.ascii_lowercase:
59 alphastart = ord('a')
60 else:
61 alphastart = ord('A')
62 letter_number = ord(letter) - alphastart
63 if one_based: letter_number += 1
64 enciphered_letter_number = letter_number * multiplier + shift
65 if one_based: enciphered_letter_number -=1
66 enciphered_letter = chr(enciphered_letter_number % 26 + alphastart)
67 return enciphered_letter
68 else:
69 return letter
70
71
72
73
74 def caesar_break(message):
75 best_key = 0
76 best_fit = float("inf")
77 for shift in range(26):
78 plaintxt = caesar_decipher_message(message, shift)
79 lettertxt = letter_frequencies(plaintxt)
80 total1 = scale_freq(lettertxt)
81 total2 = scale_freq(english_counts)
82 fit = value_diff(total2, total1)
83 if fit < best_fit:
84 best_key = shift
85 best_fit = fit
86 return best_key
87