-
Notifications
You must be signed in to change notification settings - Fork 0
/
task3.py
139 lines (116 loc) · 3.84 KB
/
task3.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import json
from utils import *
from cyphers import text_to_words
import cyphers.permutation as perm
SPACER = ' '
def get_banned_bigrams(text):
words = text_to_words(text)
alph = set()
bigrams = set()
for word in words:
for char, char_next in zip(word[:-1], word[1:]):
alph.add(char)
alph.add(char_next)
bigrams.add(char + char_next)
banned = [a + b for a in alph for b in alph if (a + b) not in bigrams]
banned.sort()
alph = ''.join(sorted(alph))
return alph, banned
def get_table(enc, banned, length):
blocks = []
for block_idx in range(0, len(enc), length):
blocks.append(enc[block_idx:block_idx + length])
table = [[True] * length for _ in range(length)]
for col_l in range(length):
for col_r in range(length):
if col_l == col_r:
table[col_l][col_r] = False
continue
for b in blocks:
cl, cr = b[col_l], b[col_r]
if not cl.isalpha() or not cr.isalpha():
continue
bigram = cl + cr
if bigram in banned:
table[col_l][col_r] = False
break
else:
table[col_l][col_r] = True
return table
def _get_tree(table, row, k, depth, used: set):
if depth == k:
return {}
if depth == k - 1:
res = {}
for col in range(k):
if table[row][col] and col not in used:
res[col + 1] = {}
return res
res = {}
for col in range(k):
if table[row][col] and col not in used:
used.add(col)
sub_node = _get_tree(table, col, k, depth + 1, used)
used.remove(col)
if sub_node:
res[col + 1] = sub_node
return res
def get_tree(table):
k = len(table)
col_trues = [[table[row][col] for row in range(k)].count(True) for col in range(k)]
cols = [idx for idx in range(k)]
cols.sort(key=lambda col: col_trues[col])
tree = {start + 1: _get_tree(table, start, k, 1, {start}) for start in cols}
tree = {key: value for (key, value) in tree.items() if value}
tree["length"] = k
return tree
def _brute(node, k, container):
for vertex in node:
container.append(int(vertex) - 1)
if len(container) == k:
yield container
else:
yield from _brute(node[vertex], k, container)
container.pop()
def brute(enc, tree):
k = tree["length"]
del tree["length"]
f = get_file_write("bruted.txt")
for key in _brute(tree, k, []):
print(perm.str_key(key) + '\r', end='')
dec = perm.decrypt(enc, key)
f.write(perm.str_key(key) + '\n')
f.write(dec + '\n\n')
f.close()
def main():
if op == 'bi':
text = read(argv[2]).lower()
alph, banned = get_banned_bigrams(text)
write('alph.txt', alph)
write('banned.txt', '\n'.join(banned))
elif op == 'gen':
perm.exec_gen_mono_key()
elif op == 'enc':
perm.exec_encrypt()
elif op == 'dec':
perm.exec_decrypt()
elif op == 'table':
enc = read(argv[2]).lower()
banned = read(argv[3]).split('\n')
length = int(argv[4])
table = get_table(enc, banned, length)
write('table.txt', '\n'.join(map(lambda x: ' '.join(map(lambda el: str(int(el)), x)), table)))
elif op == 'tree':
table = read(argv[2]).split('\n')
for idx, row in enumerate(table):
table[idx] = list(map(lambda x: bool(int(x)), row.split(' ')))
tree = get_tree(table)
write('tree.txt', json.dumps(tree, indent=4))
elif op == 'brute':
enc = read(argv[2])
tree = json.loads(read(argv[3]))
brute(enc, tree)
else:
print_wrong_op()
if __name__ == '__main__':
main()