34eac4b59c6802753bfacbc1ce972f88643338e6
[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 prohod(sl_a, sl_b, tabulka):
57     """Vrati tabulku s prohozenou dvojici sloupcu a radku."""
58     tabulka[sl_a], tabulka[sl_b] = tabulka[sl_b], tabulka[sl_a]
59     for c in tabulka.keys():
60         tabulka[c][sl_a], tabulka[c][sl_b] = tabulka[c][sl_b], tabulka[c][sl_a]
61     return
62
63 def jakobsen(zprava, ref):
64     # TODO?zacit se substituci podle poradi frekvenci
65     """Pro danou sifrovanou zpravu vrati substitucni slovnik odvozeny s pomoci
66     Jakobsenova algoritmu s danou referencni tabulkou."""
67     slovnik = dict(zip(ref.abeceda, ref.abeceda))
68     tabulka = nova_tabulka(zprava, ref.abeceda)
69     vzdal = vzdalenost(tabulka, ref.tabulka, ref.abeceda)
70
71     vzdal_old = vzdal + 1
72     while vzdal_old > vzdal:
73         vzdal_old = vzdal
74         for (x, y) in combinations(ref.abeceda, 2):
75             prohod(x, y, tabulka)
76             nova_vzdalenost = vzdalenost(tabulka, ref.tabulka, ref.abeceda)
77             if  nova_vzdalenost < vzdal:
78                 vzdal = nova_vzdalenost
79                 slovnik[x], slovnik[y] = slovnik[y], slovnik[x]
80             else:
81                 prohod(x, y, tabulka)
82     return slovnik
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])])
96
97 def __test():
98     print desifruj('Sel pes do lesa a potkal dlazebni kostku.'.upper())