merge
[krypto.git] / jakobsen.py
1 """Modul pro praci s Jakobsenovym algoritmem."""
2
3 from itertools import combinations
4 import pickle
5 from ocesavac import ocesat
6 from spolecne import MABECEDA
7
8 def nova_tabulka(zprava, abc=MABECEDA):
9     """Vraci tabulku cetnosti bigramu ve zprave nad danou abecedou."""
10     tabulka = dict()
11     for i in abc:
12         tabulka[i] = dict()
13         for j in abc:
14             tabulka[i][j] = 0
15     for i in range(len(zprava) - 1):
16         tabulka[zprava[i]][zprava[i+1]] += 1
17     celkem = sum(sum(tab2.values()) for tab2 in tabulka.values())
18     for i in abc:
19         for j in abc:
20             tabulka[i][j] /= float(celkem)
21     return tabulka
22
23 def vzdalenost(tab1, tab2, abc=MABECEDA):
24     """Vraci soucet strednich kvadratickych odchylek pro dve tabulky cetnosti
25     bigramu nad danou abecedou."""
26     rozdil = 0
27     for i in abc:
28         for j in abc:
29             rozdil += abs(tab1[i][j] - tab2[i][j])
30     return rozdil
31
32 def substituce(zprava, slovnik, abc=MABECEDA):
33     """Vrati zpravu, ve ktere jsou znaky dane abecedy nahrazenypodle daneho
34     slovniku."""
35     pole = []
36     for char in zprava:
37         if char in abc:
38             pole.append(slovnik[char])
39         else:
40             pole.append(char)
41     return pole
42
43 def poradi_dle_frekvence(zprava, abc=MABECEDA):
44     """Vrati znaky dane abecedy v poradi podle frekvence v dane zprave."""
45     freq = dict()
46     for char in abc:
47         freq[char] = 0
48     for char in zprava:
49         if char in abc:
50             freq[char] += 1
51     return sorted(freq.keys(), key=freq.get, reverse=True)
52
53 class reference:
54     pass
55
56 def jakobsen(zprava, ref):
57     """Pro danou sifrovanou zpravu vrati substitucni slovnik odvozeny s pomoci
58     Jakobsenova algoritmu s danou referencni tabulkou."""
59     slovnik = dict(zip(poradi_dle_frekvence(zprava, ref.abeceda), ref.poradi))
60     tabulka = nova_tabulka(
61                   substituce(zprava, slovnik, ref.abeceda),
62                   ref.abeceda
63                   )
64     vzdal = vzdalenost(tabulka, ref.tabulka, ref.abeceda)
65
66     vzdal_old = vzdal + 1
67     while vzdal_old > vzdal:
68         vzdal_old = vzdal
69         for (x, y) in combinations(ref.abeceda, 2):
70             slovnik[x], slovnik[y] = slovnik[y], slovnik[x]
71             nova_vzdalenost = vzdalenost(
72                      nova_tabulka(
73                          substituce(zprava, slovnik, ref.abeceda),
74                          ref.abeceda),
75                      ref.tabulka,
76                      ref.abeceda)
77             if  nova_vzdalenost < vzdal:
78                 vzdal = nova_vzdalenost
79             else:
80                 slovnik[x], slovnik[y] = slovnik[y], slovnik[x]
81     return slovnik
82     
83
84 def desifruj(zprava, mezery=True):
85     """Vrati vysledek pokusu dekodovat zpravu Jakobsenovym algoritmem."""
86     if mezery:
87         soubor = open('ref')
88     else:
89         soubor = open('bref')
90     ref = pickle.load(soubor)
91     soubor.close()
92     slovnik = jakobsen(ocesat(zprava, mezery), ref)
93     return '\n'.join([''.join(substituce(zprava, slovnik, ref.abeceda)),
94                       ' '.join(ref.abeceda),
95                       ' '.join([slovnik[c] for c in ref.abeceda])])