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
140
141
|
#!/usr/bin/env lua
local automaton = require "automaton"
local generate = require "generate"
local reading = require "reading"
local format = require "format"
local init = automaton(generate.trange(1, 25))
local function add_node (graph, id)
local node = graph[id]
if node then
return node
end
node = {
id = id,
outcoming = {},
incoming = {},
paths = {},
}
graph[id] = node
return node
end
local function add_edges (graph, state, kind)
for dst, src in ipairs(state) do
local a = add_node(graph, src)
local b = add_node(graph, dst)
a.outcoming[kind] = b
b.incoming[kind] = a
end
end
local graph = {}
add_edges(graph, init:left(), "left")
add_edges(graph, init:right(), "right")
add_edges(graph, init:pivot(), "centre")
add_edges(graph, init:up(), "up")
add_edges(graph, init:down(), "down")
local map = {
centre = 0,
up = 1,
right = 2,
down = 3,
left = 4,
}
local function trigram (path)
return reading.trigram_to_value(
map[path[1]],
map[path[2]],
map[path[3]])
end
local function shallow_copy (obj)
local new = {}
for k, v in ipairs(obj) do
new[k] = v
end
return new
end
local function generate_paths_from (start, length)
local queue = {{node=start, length=0, path={}}}
while #queue > 0 do
local entry = table.remove(queue, 1)
if entry.length == length then
local paths = entry.node.paths[start.id] or {}
table.insert(paths, entry.path)
entry.node.paths[start.id] = paths
end
if entry.length < length then
for kind, node in pairs(entry.node.incoming) do
local path = shallow_copy(entry.path)
table.insert(path, 1, kind)
table.insert(queue, {node=node, length=entry.length + 1, path=path})
end
end
end
end
local function error_no_path_between (start, dest)
if not start.paths[dest.id] then
io.stderr:write(string.format("cannot move from %d to %d\n", start.id, dest.id))
end
end
generate_paths_from(graph[3], 3)
generate_paths_from(graph[19], 3)
for _, node in ipairs(graph) do
for target, paths in pairs(node.paths) do
for _, path in ipairs(paths) do
-- print(string.format("%d,%d,%d,%s,%s,%s", node.id, target, trigram(path), path[1], path[2], path[3]))
end
end
error_no_path_between(node, graph[3])
error_no_path_between(node, graph[19])
end
local function stupid_invert (obj)
local lookup = {}
for k, v in pairs(obj) do
lookup[v] = k
end
return lookup
end
local function encode (graph, state, message)
state = automaton(state)
local lookup = stupid_invert(state)
local values = {}
for i=1, #message do
local node = graph[lookup[message:sub(i, i)]]
if not node then
error(message:sub(i, i))
end
local output = 3
if (i - 1) % 3 == 1 then
output = 19
end
local path = node.paths[output][math.random(1, #node.paths[output])]
table.insert(values, trigram(path))
state = state:apply(map[path[1]]):apply(map[path[2]]):apply(map[path[3]])
lookup = stupid_invert(state)
end
return values
end
for i=1, 5 do
print(format.csv(encode(graph, "abcdefghiwklm opqrstuvxyz", "we cam try this method to see what kimd of potemial ciphertext we will get out of it")))
print(format.csv(encode(graph, "abcdefghiwklm opqrstuvxyz", "amd them try it with amother plaimtext iust to make sure this actually works as expected with lomger texts too")))
end
|