17 bool continue_through_exit_ep(
const Endpoint* exit_ep,
const u32 current_depth)
19 if (exit_ep ==
nullptr)
26 if (current_depth != 0)
30 else if (control_types.find(exit_ep->get_pin()->get_type()) != control_types.end())
39 bool continue_through_entry_ep(
const Endpoint* entry_ep,
const u32 current_depth)
41 if (entry_ep ==
nullptr)
46 if (control_types.find(entry_ep->get_pin()->get_type()) != control_types.end())
51 const auto* gt = entry_ep->get_gate()->get_type();
66 bool operator==(
const GraphCandidate& rhs)
const
68 return this->size == rhs.size && this->in_reg == rhs.in_reg && this->out_reg == rhs.out_reg;
71 bool operator<(
const GraphCandidate& rhs)
const
73 return this->size > rhs.size || (this->size == rhs.size && this->in_reg > rhs.in_reg) || (this->size == rhs.size && this->in_reg == rhs.in_reg && this->out_reg > rhs.out_reg);
77 igraph_error_t get_saturating_neighborhoods(
const igraph_t* graph, igraph_vector_int_t* in_set, igraph_vector_int_t* out_set, igraph_integer_t node, igraph_integer_t timeout)
79 igraph_integer_t no_of_nodes = igraph_vcount(graph);
80 igraph_integer_t i, j, k;
82 igraph_vector_int_t current_hood, previous_hood;
83 igraph_vector_int_t* current_hood_p = ¤t_hood;
84 igraph_vector_int_t* previous_hood_p = &previous_hood;
85 igraph_vector_int_t tmp;
89 IGRAPH_ERROR(
"Negative timeout", IGRAPH_EINVAL);
92 added = IGRAPH_CALLOC(no_of_nodes, igraph_bool_t);
93 IGRAPH_CHECK_OOM(added,
"Cannot calculate neighborhood size.");
94 IGRAPH_FINALLY(igraph_free, added);
96 IGRAPH_VECTOR_INT_INIT_FINALLY(current_hood_p, 0);
97 IGRAPH_VECTOR_INT_INIT_FINALLY(previous_hood_p, 0);
98 IGRAPH_VECTOR_INT_INIT_FINALLY(&tmp, 0);
100 IGRAPH_CHECK(igraph_vector_int_init(in_set, 0));
101 IGRAPH_CHECK(igraph_vector_int_init(out_set, 0));
102 igraph_vector_int_clear(in_set);
103 igraph_vector_int_clear(out_set);
105 IGRAPH_CHECK(igraph_vector_int_push_back(current_hood_p, node));
107 igraph_integer_t previous_size, current_size;
109 for (i = 0; i < timeout; i++)
111 previous_size = igraph_vector_int_size(previous_hood_p);
112 current_size = igraph_vector_int_size(current_hood_p);
114 if (previous_size < current_size)
116 igraph_vector_int_swap(previous_hood_p, current_hood_p);
117 igraph_vector_int_clear(current_hood_p);
119 memset(added,
false, no_of_nodes *
sizeof(igraph_bool_t));
121 for (j = 0; j < current_size; j++)
123 igraph_integer_t actnode = VECTOR(*previous_hood_p)[j];
124 igraph_vector_int_clear(&tmp);
126 IGRAPH_CHECK(igraph_neighbors(graph, &tmp, actnode, IGRAPH_OUT, IGRAPH_LOOPS_TWICE,
true));
128 for (k = 0; k < igraph_vector_int_size(&tmp); k++)
130 igraph_integer_t nei = VECTOR(tmp)[k];
134 IGRAPH_CHECK(igraph_vector_int_push_back(current_hood_p, nei));
141 if (previous_size == current_size)
143 IGRAPH_CHECK(igraph_vector_int_update(in_set, previous_hood_p));
144 IGRAPH_CHECK(igraph_vector_int_update(out_set, current_hood_p));
151 igraph_vector_int_destroy(current_hood_p);
152 igraph_vector_int_destroy(previous_hood_p);
153 igraph_vector_int_destroy(&tmp);
155 IGRAPH_FINALLY_CLEAN(4);
157 return IGRAPH_SUCCESS;
160 igraph_error_t get_saturating_neighborhoods_scc(
const igraph_t* graph,
161 igraph_vector_int_t* in_set,
162 igraph_vector_int_t* out_set,
163 igraph_integer_t node,
164 igraph_integer_t timeout,
165 std::map<std::set<u32>, igraph_vector_int_t*>& cache)
167 igraph_integer_t no_of_nodes = igraph_vcount(graph);
168 igraph_integer_t i, j, k;
169 igraph_bool_t* added;
170 igraph_vector_int_t current_hood, previous_hood;
171 igraph_vector_int_t current_component, previous_component;
172 igraph_vector_int_t* current_hood_p = ¤t_hood;
173 igraph_vector_int_t* previous_hood_p = &previous_hood;
174 igraph_vector_int_t* current_component_p = ¤t_component;
175 igraph_vector_int_t* previous_component_p = &previous_component;
176 igraph_vector_int_t tmp;
180 IGRAPH_ERROR(
"Negative timeout", IGRAPH_EINVAL);
183 added = IGRAPH_CALLOC(no_of_nodes, igraph_bool_t);
184 IGRAPH_CHECK_OOM(added,
"Cannot calculate neighborhood size.");
185 IGRAPH_FINALLY(igraph_free, added);
187 IGRAPH_VECTOR_INT_INIT_FINALLY(current_hood_p, 0);
188 IGRAPH_VECTOR_INT_INIT_FINALLY(previous_hood_p, 0);
189 IGRAPH_VECTOR_INT_INIT_FINALLY(current_component_p, 0);
190 IGRAPH_VECTOR_INT_INIT_FINALLY(previous_component_p, 0);
191 IGRAPH_VECTOR_INT_INIT_FINALLY(&tmp, 0);
193 IGRAPH_CHECK(igraph_vector_int_init(in_set, 0));
194 IGRAPH_CHECK(igraph_vector_int_init(out_set, 0));
195 igraph_vector_int_clear(in_set);
196 igraph_vector_int_clear(out_set);
198 IGRAPH_CHECK(igraph_vector_int_push_back(current_hood_p, node));
199 IGRAPH_CHECK(igraph_vector_int_push_back(current_component_p, node));
201 igraph_integer_t previous_size, current_size;
203 for (i = 0; i < timeout; i++)
205 previous_size = igraph_vector_int_size(previous_component_p);
206 current_size = igraph_vector_int_size(current_component_p);
207 u32 current_hood_size = igraph_vector_int_size(current_hood_p);
209 if (previous_size < current_size || current_size == 1)
212 igraph_vector_int_swap(previous_hood_p, current_hood_p);
213 igraph_vector_int_swap(previous_component_p, current_component_p);
214 igraph_vector_int_clear(current_hood_p);
215 igraph_vector_int_clear(current_component_p);
218 memset(added,
false, no_of_nodes *
sizeof(igraph_bool_t));
220 std::set<u32> cache_key;
221 for (j = 0; j < current_hood_size; j++)
223 igraph_integer_t actnode = VECTOR(*previous_hood_p)[j];
224 igraph_vector_int_clear(&tmp);
226 IGRAPH_CHECK(igraph_neighbors(graph, &tmp, actnode, IGRAPH_OUT, IGRAPH_LOOPS_TWICE,
true));
228 for (k = 0; k < igraph_vector_int_size(&tmp); k++)
230 igraph_integer_t nei = VECTOR(tmp)[k];
234 IGRAPH_CHECK(igraph_vector_int_push_back(current_hood_p, nei));
235 cache_key.insert(nei);
245 if (
const auto cache_it = cache.find(cache_key); cache_it != cache.end())
247 IGRAPH_CHECK(igraph_vector_int_update(current_component_p, cache_it->second));
252 igraph_vs_t subgraph_vertices = igraph_vss_vector(current_hood_p);
253 IGRAPH_FINALLY(igraph_vs_destroy, &subgraph_vertices);
254 igraph_vector_int_t vertex_map;
255 IGRAPH_VECTOR_INT_INIT_FINALLY(&vertex_map, igraph_vector_int_size(current_hood_p));
256 IGRAPH_CHECK(igraph_induced_subgraph_map(graph, &subgraph, subgraph_vertices, IGRAPH_SUBGRAPH_CREATE_FROM_SCRATCH,
nullptr, &vertex_map));
257 IGRAPH_FINALLY(igraph_destroy, &subgraph);
259 igraph_vector_int_t membership, csize;
260 IGRAPH_VECTOR_INT_INIT_FINALLY(&membership, 0);
261 IGRAPH_VECTOR_INT_INIT_FINALLY(&csize, 0);
262 IGRAPH_CHECK(igraph_connected_components(&subgraph, &membership, &csize,
nullptr, IGRAPH_STRONG));
264 u32 max_id = igraph_vector_int_which_max(&csize);
265 u32 num_subgraph_vertices = igraph_vcount(&subgraph);
266 for (
i32 i = 0; i < num_subgraph_vertices; i++)
268 u32 cid = VECTOR(membership)[i];
271 IGRAPH_CHECK(igraph_vector_int_push_back(current_component_p, VECTOR(vertex_map)[i]));
275 igraph_vs_destroy(&subgraph_vertices);
276 igraph_vector_int_destroy(&vertex_map);
277 igraph_vector_int_destroy(&membership);
278 igraph_vector_int_destroy(&csize);
279 igraph_destroy(&subgraph);
280 IGRAPH_FINALLY_CLEAN(5);
282 igraph_vector_int_t* cache_tmp =
new igraph_vector_int_t;
283 IGRAPH_CHECK(igraph_vector_int_init(cache_tmp, 0));
284 IGRAPH_CHECK(igraph_vector_int_update(cache_tmp, current_component_p));
285 cache[cache_key] = cache_tmp;
290 if (previous_size == current_size)
292 IGRAPH_CHECK(igraph_vector_int_update(in_set, previous_component_p));
293 IGRAPH_CHECK(igraph_vector_int_update(out_set, current_component_p));
300 igraph_vector_int_destroy(current_hood_p);
301 igraph_vector_int_destroy(previous_hood_p);
302 igraph_vector_int_destroy(current_component_p);
303 igraph_vector_int_destroy(previous_component_p);
304 igraph_vector_int_destroy(&tmp);
306 IGRAPH_FINALLY_CLEAN(6);
308 return IGRAPH_SUCCESS;
316 return ERR(
"netlist is a nullptr");
319 log_info(
"hawkeye",
"start detecting state register candidates...");
320 auto start = std::chrono::system_clock::now();
323 std::map<Gate*, std::set<Gate*>> ff_map;
324 std::unordered_map<const Net*, std::set<Gate*>> cache = {};
326 for (
auto* sg : start_gates)
328 if (
const auto res = nl_dec.get_next_matching_gates(
329 sg,
true, [](
const Gate* g) { return g->get_type()->has_property(GateTypeProperty::ff); },
false, continue_through_exit_ep, continue_through_entry_ep);
332 ff_map[sg] = res.get();
336 return ERR(res.get_error());
343 return ERR(res.get_error());
345 auto base_graph = res.get();
347 const auto start_vertices_res = base_graph->get_vertices_from_gates(start_ffs.empty() ? start_gates : start_ffs);
348 if (start_vertices_res.is_error())
350 return ERR(start_vertices_res.get_error());
352 auto start_vertices = start_vertices_res.get();
354 std::set<RegisterCandidate> candidates;
355 for (
const auto& config : configs)
357 auto tmp_graph_res = base_graph->copy();
358 if (tmp_graph_res.is_error())
360 return ERR(tmp_graph_res.get_error());
362 auto tmp_graph = tmp_graph_res.get();
364 std::map<Gate*, std::set<Gate*>> filtered_map;
367 filtered_map = std::move(ff_map);
368 if (
const auto edge_res = tmp_graph->add_edges(ff_map); edge_res.is_error())
370 return ERR(edge_res.get_error());
375 std::map<const GateType*, std::set<const GateType*>> allowed_gate_type_map;
377 for (
const auto& gt_list : config.equivalent_types)
379 std::set<const GateType*> types;
380 for (
const auto& gt_name : gt_list)
382 types.insert(gl->get_gate_type_by_name(gt_name));
385 for (
const auto* gt : types)
387 allowed_gate_type_map[gt] = types;
391 for (
const auto& [src, dsts] : ff_map)
393 for (
auto* dst : dsts)
395 const auto* src_type = src->get_type();
396 const auto* dst_type = dst->get_type();
397 if (src_type != dst_type)
399 if (
const auto src_it = allowed_gate_type_map.find(src_type); src_it != allowed_gate_type_map.end())
401 const auto& allowed_gates = std::get<1>(*src_it);
402 if (allowed_gates.find(dst_type) == allowed_gates.end())
413 filtered_map[src].insert(dst);
419 std::unordered_map<const Gate*, std::map<PinType, const Net*>> control_map;
420 for (
const auto* gate : start_gates)
422 control_map[gate] = std::map<PinType, const Net*>();
424 for (
const auto& ep : gate->get_fan_in_endpoints())
426 if (
auto pin_type = ep->get_pin()->get_type(); control_types.find(pin_type) != control_types.end())
428 control_map[gate][pin_type] = ep->get_net();
433 for (
const auto& [src, dsts] : ff_map)
435 for (
auto* dst : dsts)
437 if (control_map.at(src) != control_map.at(dst))
442 filtered_map[src].insert(dst);
448 std::unordered_map<const Gate*, std::set<PinType>> control_map;
449 for (
const auto* gate : start_gates)
451 control_map[gate] = std::set<PinType>();
453 for (
const auto& ep : gate->get_fan_in_endpoints())
455 auto sources = ep->get_net()->get_sources();
456 if (sources.size() != 1)
460 if (sources.at(0)->get_gate()->is_gnd_gate() || sources.at(0)->get_gate()->is_vcc_gate())
465 if (
auto pin_type = ep->get_pin()->get_type(); control_types.find(pin_type) != control_types.end())
467 control_map[gate].insert(pin_type);
472 for (
const auto& [src, dsts] : ff_map)
474 for (
auto* dst : dsts)
481 if (control_map.at(src) != control_map.at(dst))
486 filtered_map[src].insert(dst);
491 if (
const auto edge_res = tmp_graph->add_edges(filtered_map); edge_res.is_error())
493 return ERR(edge_res.get_error());
496 igraph_vector_int_t in_set, out_set;
497 if (
const auto res = igraph_vector_int_init(&in_set, 0); res != IGRAPH_SUCCESS)
499 return ERR(igraph_strerror(res));
502 if (
const auto res = igraph_vector_int_init(&out_set, 0); res != IGRAPH_SUCCESS)
504 igraph_vector_int_destroy(&in_set);
505 return ERR(igraph_strerror(res));
508 std::set<GraphCandidate> graph_candidates;
512 for (
const auto v : start_vertices)
514 igraph_vector_int_clear(&in_set);
515 igraph_vector_int_clear(&out_set);
517 if (
const auto res = get_saturating_neighborhoods(tmp_graph->get_graph(), &in_set, &out_set, v, config.timeout); res != IGRAPH_SUCCESS)
519 igraph_vector_int_destroy(&in_set);
520 igraph_vector_int_destroy(&out_set);
521 return ERR(igraph_strerror(res));
524 u32 size = igraph_vector_int_size(&out_set);
525 if (
size <= config.min_register_size)
532 for (
u32 i = 0; i < igraph_vector_int_size(&in_set); i++)
534 c.in_reg.insert(VECTOR(in_set)[i]);
536 for (
u32 i = 0; i < igraph_vector_int_size(&out_set); i++)
538 c.out_reg.insert(VECTOR(out_set)[i]);
540 graph_candidates.insert(c);
545 std::map<std::set<u32>, igraph_vector_int_t*> scc_cache;
547 for (
const auto v : start_vertices)
549 igraph_vector_int_clear(&in_set);
550 igraph_vector_int_clear(&out_set);
552 if (
const auto res = get_saturating_neighborhoods_scc(tmp_graph->get_graph(), &in_set, &out_set, v, config.timeout, scc_cache); res != IGRAPH_SUCCESS)
554 igraph_vector_int_destroy(&in_set);
555 igraph_vector_int_destroy(&out_set);
556 for (
auto& [_, comp] : scc_cache)
558 igraph_vector_int_destroy(comp);
561 return ERR(igraph_strerror(res));
564 u32 size = igraph_vector_int_size(&out_set);
565 if (
size <= config.min_register_size)
572 for (
u32 i = 0; i < igraph_vector_int_size(&in_set); i++)
574 c.in_reg.insert(VECTOR(in_set)[i]);
576 for (
u32 i = 0; i < igraph_vector_int_size(&out_set); i++)
578 c.out_reg.insert(VECTOR(out_set)[i]);
580 graph_candidates.insert(c);
583 for (
auto& [_, comp] : scc_cache)
585 igraph_vector_int_destroy(comp);
590 igraph_vector_int_destroy(&in_set);
591 igraph_vector_int_destroy(&out_set);
593 for (
const auto& gc : graph_candidates)
597 if (
auto out_reg_res = tmp_graph->get_gates_set_from_vertices(gc.out_reg); out_reg_res.is_ok())
603 return ERR(out_reg_res.get_error());
606 if (gc.in_reg == gc.out_reg)
613 if (
auto in_reg_res = tmp_graph->get_gates_set_from_vertices(gc.in_reg); in_reg_res.is_ok())
615 in_reg = in_reg_res.get();
620 return ERR(in_reg_res.get_error());
626 std::set<const RegisterCandidate*> candidates_to_delete;
627 for (
auto outer_it = candidates.begin(); outer_it != candidates.end(); outer_it++)
629 for (
auto inner_it = std::next(outer_it, 1); inner_it != candidates.end(); inner_it++)
631 if (std::includes(outer_it->get_output_reg().begin(), outer_it->get_output_reg().end(), inner_it->get_output_reg().begin(), inner_it->get_output_reg().end()))
633 candidates_to_delete.insert(&(*outer_it));
638 if (outer_it->get_size() < min_state_size)
640 candidates_to_delete.insert(&(*outer_it));
644 for (
const auto* c : candidates_to_delete)
646 candidates.erase(*c);
649 auto duration_in_seconds = std::chrono::duration<double>(std::chrono::system_clock::now() - start).count();
650 if (candidates.size() == 1)
652 log_info(
"hawkeye",
"detected {} state register candidate in {} seconds", candidates.size(), duration_in_seconds);
656 log_info(
"hawkeye",
"detected {} state register candidates in {} seconds", candidates.size(), duration_in_seconds);
659 return OK(std::vector<RegisterCandidate>(candidates.begin(), candidates.end()));
This file contains the function for HAWKEYE's candidate search as well as a struct for configuring th...
GateType * get_type() const
const std::vector< Gate * > & get_gates() const
const GateLibrary * get_gate_library() const
static Result< std::unique_ptr< NetlistGraph > > from_netlist_no_edges(Netlist *nl, const std::vector< Gate * > &gates={})
Create an empty directed graph from a netlist.
A register candidate discovered by HAWKEYE.
#define log_info(channel,...)
Result< std::vector< RegisterCandidate > > detect_candidates(Netlist *nl, const std::vector< DetectionConfiguration > &configs, u32 min_state_size=40, const std::vector< Gate * > &start_ffs={})
Attempt to locate candidates for symmetric cryptographic implementations within a gate-level netlist.
This file contains functions related to neighborhoods in graphs.
This file contains the class that holds a netlist graph.
@ CHECK_NETS
If two flip-flops ff1 and ff2 are connected through combinational logic and are controlled through th...
@ CHECK_TYPE
If two flip-flops ff1 and ff2 are connected through combinational logic and are of the same gate type...
@ CHECK_FF
If two flip-flops ff1 and ff2 are connected through combinational logic, an edge is added such that (...
@ CHECK_PINS
If two flip-flops ff1 and ff2 are connected through combinational logic and are controlled through th...
@ CHECK_SCC
Use SCC detection within the currently explored neighborhood of a start flip-flop.
@ NONE
Do not use SCC detection and instead resort to the simple neighborhood discovery algorithm.