jakobsen
[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     """Pro danou sifrovanou zpravu vrati substitucni slovnik odvozeny s pomoci
65     Jakobsenova algoritmu s danou referencni tabulkou."""
66     slovnik = dict(zip(ref.abeceda, ref.abeceda))
67     tabulka = nova_tabulka(zprava, ref.abeceda)
68     vzdal = vzdalenost(tabulka, ref.tabulka, ref.abeceda)
69
70     vzdal_old = vzdal + 1
71     while vzdal_old > vzdal:
72         vzdal_old = vzdal
73         for (x, y) in combinations(ref.abeceda, 2):
74             prohod(x, y, tabulka)
75             nova_vzdalenost = vzdalenost(tabulka, ref.tabulka, ref.abeceda)
76             if  nova_vzdalenost < vzdal:
77                 vzdal = nova_vzdalenost
78                 slovnik[x], slovnik[y] = slovnik[y], slovnik[x]
79             else:
80                 prohod(x, y, tabulka)
81     return slovnik
82     
83 def desifruj(zprava, mezery=True):
84     """Vrati vysledek pokusu dekodovat zpravu Jakobsenovym algoritmem."""
85     if mezery:
86         soubor = open('ref')
87     else:
88         soubor = open('bref')
89     ref = pickle.load(soubor)
90     soubor.close()
91     zprava = substituce(zprava, dict(zip(poradi_dle_frekvence(zprava, ref.abeceda), ref.poradi)), ref.abeceda)
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('Mxbhfxn cbfbhinpr, wnx fv f gvzuyr cbenqv.'.upper())
99
100 def __test2():
101     print desifruj('Sel pes do lesa a potkal dlazebni kostku. Chtelo by to jeste o neco delsi test, to tedy jo.'.upper())