|
| 1 | +""" This module implements `Dijkstra's algorithm |
| 2 | +<https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm>`_ based on |
| 3 | +oblivious RAM. """ |
| 4 | + |
| 5 | + |
1 | 6 | from Compiler.oram import *
|
2 | 7 |
|
3 | 8 | from Compiler.program import Program
|
@@ -222,7 +227,21 @@ def dump(self, msg=''):
|
222 | 227 | print_ln()
|
223 | 228 | print_ln()
|
224 | 229 |
|
225 |
| -def dijkstra(source, edges, e_index, oram_type, n_loops=None, int_type=None): |
| 230 | +def dijkstra(source, edges, e_index, oram_type, n_loops=None, int_type=None, |
| 231 | + debug=False): |
| 232 | + """ Securely compute Dijstra's algorithm on a secret graph. See |
| 233 | + :download:`../Programs/Source/dijkstra_example.mpc` for an |
| 234 | + explanation of the required inputs. |
| 235 | +
|
| 236 | + :param source: source node (secret or clear-text integer) |
| 237 | + :param edges: ORAM representation of edges |
| 238 | + :param e_index: ORAM representation of vertices |
| 239 | + :param oram_type: ORAM type to use internally (default: |
| 240 | + :py:func:`~Compiler.oram.OptimalORAM`) |
| 241 | + :param n_loops: when to stop (default: number of edges) |
| 242 | + :param int_type: secret integer type (default: sint) |
| 243 | +
|
| 244 | + """ |
226 | 245 | vert_loops = n_loops * e_index.size // edges.size \
|
227 | 246 | if n_loops else -1
|
228 | 247 | dist = oram_type(e_index.size, entry_size=(32,log2(e_index.size)), \
|
@@ -267,27 +286,46 @@ def f(i):
|
267 | 286 | dist.access(v, (basic_type(alt), u), is_shorter)
|
268 | 287 | #previous.access(v, u, is_shorter)
|
269 | 288 | Q.update(v, basic_type(alt), is_shorter)
|
270 |
| - print_ln('u: %s, v: %s, alt: %s, dv: %s, first visit: %s', \ |
271 |
| - u.reveal(), v.reveal(), alt.reveal(), dv[0].reveal(), \ |
272 |
| - not_visited.reveal()) |
| 289 | + if debug: |
| 290 | + print_ln('u: %s, v: %s, alt: %s, dv: %s, first visit: %s, ' |
| 291 | + 'shorter: %s, running: %s, queue size: %s, last edge: %s', |
| 292 | + u.reveal(), v.reveal(), alt.reveal(), dv[0].reveal(), |
| 293 | + not_visited.reveal(), is_shorter.reveal(), |
| 294 | + running.reveal(), Q.size.reveal(), last_edge.reveal()) |
273 | 295 | return dist
|
274 | 296 |
|
275 | 297 | def convert_graph(G):
|
| 298 | + """ Convert a `NetworkX directed graph |
| 299 | + <https://networkx.org/documentation/stable/reference/classes/digraph.html>`_ |
| 300 | + to the cleartext representation of what :py:func:`dijkstra` expects. """ |
| 301 | + G = G.copy() |
| 302 | + for u in G: |
| 303 | + for v in G[u]: |
| 304 | + G[u][v].setdefault('weight', 1) |
276 | 305 | edges = [None] * (2 * G.size())
|
277 | 306 | e_index = [None] * (len(G))
|
278 | 307 | i = 0
|
279 |
| - for v in G: |
| 308 | + for v in sorted(G): |
280 | 309 | e_index[v] = i
|
281 |
| - for u in G[v]: |
| 310 | + for u in sorted(G[v]): |
282 | 311 | edges[i] = [u, G[v][u]['weight'], 0]
|
283 | 312 | i += 1
|
| 313 | + if not G[v]: |
| 314 | + edges[i] = [v, 0, 0] |
| 315 | + i += 1 |
284 | 316 | edges[i-1][-1] = 1
|
285 |
| - return edges, e_index |
| 317 | + return list(filter(lambda x: x, edges)), e_index |
286 | 318 |
|
287 |
| -def test_dijkstra(G, source, oram_type=ORAM, n_loops=None, int_type=sint): |
288 |
| - for u in G: |
289 |
| - for v in G[u]: |
290 |
| - G[u][v].setdefault('weight', 1) |
| 319 | +def test_dijkstra(G, source, oram_type=ORAM, n_loops=None, |
| 320 | + int_type=sint): |
| 321 | + """ Securely compute Dijstra's algorithm on a cleartext graph. |
| 322 | +
|
| 323 | + :param G: directed graph with NetworkX interface |
| 324 | + :param source: source node (secret or clear-text integer) |
| 325 | + :param n_loops: when to stop (default: number of edges) |
| 326 | + :param int_type: secret integer type (default: sint) |
| 327 | +
|
| 328 | + """ |
291 | 329 | edges_list, e_index_list = convert_graph(G)
|
292 | 330 | edges = oram_type(len(edges_list), \
|
293 | 331 | entry_size=(log2(len(G)), log2(len(G)), 1), \
|
|
0 commit comments