HAL  v4.5.0-124-g47ab54673
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
candidate_search.cpp
Go to the documentation of this file.
2 
7 #include "hal_core/netlist/net.h"
11 
12 #include <algorithm>
13 
14 namespace hal
15 {
16  namespace hawkeye
17  {
18  namespace
19  {
20  static std::set<PinType> control_types = {PinType::enable, PinType::clock, PinType::set, PinType::reset};
21 
22  bool continue_through_exit_ep(const Endpoint* exit_ep, const u32 current_depth)
23  {
24  if (exit_ep == nullptr)
25  {
26  return false;
27  }
28 
29  if (exit_ep->get_gate()->get_type()->has_property(GateTypeProperty::ff))
30  {
31  if (current_depth != 0)
32  {
33  return false;
34  }
35  else if (control_types.find(exit_ep->get_pin()->get_type()) != control_types.end())
36  {
37  return false;
38  }
39  }
40 
41  return true;
42  }
43 
44  bool continue_through_entry_ep(const Endpoint* entry_ep, const u32 current_depth)
45  {
46  if (entry_ep == nullptr)
47  {
48  return false;
49  }
50 
51  if (control_types.find(entry_ep->get_pin()->get_type()) != control_types.end())
52  {
53  return false;
54  }
55 
56  const auto* gt = entry_ep->get_gate()->get_type();
57  if (gt->has_property(GateTypeProperty::ram))
58  {
59  return false;
60  }
61 
62  return true;
63  }
64 
65  struct GraphCandidate
66  {
68  std::set<u32> in_reg;
69  std::set<u32> out_reg;
70 
71  bool operator==(const GraphCandidate& rhs) const
72  {
73  return this->size == rhs.size && this->in_reg == rhs.in_reg && this->out_reg == rhs.out_reg;
74  }
75 
76  bool operator<(const GraphCandidate& rhs) const
77  {
78  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);
79  }
80  };
81 
82  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)
83  {
84  igraph_integer_t no_of_nodes = igraph_vcount(graph);
85  igraph_integer_t i, j, k;
86  igraph_bool_t* added;
87  igraph_vector_int_t current_hood, previous_hood;
88  igraph_vector_int_t* current_hood_p = &current_hood;
89  igraph_vector_int_t* previous_hood_p = &previous_hood;
90  igraph_vector_int_t tmp;
91 
92  if (timeout < 0)
93  {
94  IGRAPH_ERROR("Negative timeout", IGRAPH_EINVAL);
95  }
96 
97  added = IGRAPH_CALLOC(no_of_nodes, igraph_bool_t);
98  IGRAPH_CHECK_OOM(added, "Cannot calculate neighborhood size.");
99  IGRAPH_FINALLY(igraph_free, added);
100 
101  IGRAPH_VECTOR_INT_INIT_FINALLY(current_hood_p, 0);
102  IGRAPH_VECTOR_INT_INIT_FINALLY(previous_hood_p, 0);
103  IGRAPH_VECTOR_INT_INIT_FINALLY(&tmp, 0);
104 
105  IGRAPH_CHECK(igraph_vector_int_init(in_set, 0));
106  IGRAPH_CHECK(igraph_vector_int_init(out_set, 0));
107  igraph_vector_int_clear(in_set);
108  igraph_vector_int_clear(out_set);
109 
110  IGRAPH_CHECK(igraph_vector_int_push_back(current_hood_p, node));
111 
112  igraph_integer_t previous_size, current_size;
113 
114  for (i = 0; i < timeout; i++)
115  {
116  previous_size = igraph_vector_int_size(previous_hood_p);
117  current_size = igraph_vector_int_size(current_hood_p);
118 
119  if (previous_size < current_size)
120  {
121  igraph_vector_int_swap(previous_hood_p, current_hood_p);
122  igraph_vector_int_clear(current_hood_p);
123 
124  memset(added, false, no_of_nodes * sizeof(igraph_bool_t));
125 
126  for (j = 0; j < current_size; j++)
127  {
128  igraph_integer_t actnode = VECTOR(*previous_hood_p)[j];
129  igraph_vector_int_clear(&tmp);
130  // IGRAPH_LOOPS_TWICE and multiple = true keep every neighbor in the result, duplicates are filtered by `added` below
131  IGRAPH_CHECK(igraph_neighbors(graph, &tmp, actnode, IGRAPH_OUT, IGRAPH_LOOPS_TWICE, true));
132 
133  for (k = 0; k < igraph_vector_int_size(&tmp); k++)
134  {
135  igraph_integer_t nei = VECTOR(tmp)[k];
136  if (!added[nei])
137  {
138  added[nei] = true;
139  IGRAPH_CHECK(igraph_vector_int_push_back(current_hood_p, nei));
140  }
141  }
142  }
143  }
144  else
145  {
146  if (previous_size == current_size)
147  {
148  IGRAPH_CHECK(igraph_vector_int_update(in_set, previous_hood_p));
149  IGRAPH_CHECK(igraph_vector_int_update(out_set, current_hood_p));
150  }
151 
152  break;
153  }
154  }
155 
156  igraph_vector_int_destroy(current_hood_p);
157  igraph_vector_int_destroy(previous_hood_p);
158  igraph_vector_int_destroy(&tmp);
159  IGRAPH_FREE(added);
160  IGRAPH_FINALLY_CLEAN(4);
161 
162  return IGRAPH_SUCCESS;
163  }
164 
165  igraph_error_t get_saturating_neighborhoods_scc(const igraph_t* graph,
166  igraph_vector_int_t* in_set,
167  igraph_vector_int_t* out_set,
168  igraph_integer_t node,
169  igraph_integer_t timeout,
170  std::map<std::set<u32>, igraph_vector_int_t*>& cache)
171  {
172  igraph_integer_t no_of_nodes = igraph_vcount(graph);
173  igraph_integer_t i, j, k;
174  igraph_bool_t* added;
175  igraph_vector_int_t current_hood, previous_hood;
176  igraph_vector_int_t current_component, previous_component;
177  igraph_vector_int_t* current_hood_p = &current_hood;
178  igraph_vector_int_t* previous_hood_p = &previous_hood;
179  igraph_vector_int_t* current_component_p = &current_component;
180  igraph_vector_int_t* previous_component_p = &previous_component;
181  igraph_vector_int_t tmp;
182 
183  if (timeout < 0)
184  {
185  IGRAPH_ERROR("Negative timeout", IGRAPH_EINVAL);
186  }
187 
188  added = IGRAPH_CALLOC(no_of_nodes, igraph_bool_t);
189  IGRAPH_CHECK_OOM(added, "Cannot calculate neighborhood size.");
190  IGRAPH_FINALLY(igraph_free, added);
191 
192  IGRAPH_VECTOR_INT_INIT_FINALLY(current_hood_p, 0);
193  IGRAPH_VECTOR_INT_INIT_FINALLY(previous_hood_p, 0);
194  IGRAPH_VECTOR_INT_INIT_FINALLY(current_component_p, 0);
195  IGRAPH_VECTOR_INT_INIT_FINALLY(previous_component_p, 0);
196  IGRAPH_VECTOR_INT_INIT_FINALLY(&tmp, 0);
197 
198  IGRAPH_CHECK(igraph_vector_int_init(in_set, 0));
199  IGRAPH_CHECK(igraph_vector_int_init(out_set, 0));
200  igraph_vector_int_clear(in_set);
201  igraph_vector_int_clear(out_set);
202 
203  IGRAPH_CHECK(igraph_vector_int_push_back(current_hood_p, node));
204  IGRAPH_CHECK(igraph_vector_int_push_back(current_component_p, node));
205 
206  igraph_integer_t previous_size, current_size;
207 
208  for (i = 0; i < timeout; i++)
209  {
210  previous_size = igraph_vector_int_size(previous_component_p);
211  current_size = igraph_vector_int_size(current_component_p);
212  u32 current_hood_size = igraph_vector_int_size(current_hood_p);
213 
214  if (previous_size < current_size || current_size == 1)
215  {
216  // move current objects to previous
217  igraph_vector_int_swap(previous_hood_p, current_hood_p);
218  igraph_vector_int_swap(previous_component_p, current_component_p);
219  igraph_vector_int_clear(current_hood_p);
220  igraph_vector_int_clear(current_component_p);
221 
222  // clear flags of added vertices
223  memset(added, false, no_of_nodes * sizeof(igraph_bool_t));
224 
225  std::set<u32> cache_key;
226  for (j = 0; j < current_hood_size; j++)
227  {
228  igraph_integer_t actnode = VECTOR(*previous_hood_p)[j];
229  igraph_vector_int_clear(&tmp);
230  // IGRAPH_LOOPS_TWICE and multiple = true keep every neighbor in the result, duplicates are filtered by `added` below
231  IGRAPH_CHECK(igraph_neighbors(graph, &tmp, actnode, IGRAPH_OUT, IGRAPH_LOOPS_TWICE, true));
232 
233  for (k = 0; k < igraph_vector_int_size(&tmp); k++)
234  {
235  igraph_integer_t nei = VECTOR(tmp)[k];
236  if (!added[nei])
237  {
238  added[nei] = true;
239  IGRAPH_CHECK(igraph_vector_int_push_back(current_hood_p, nei));
240  cache_key.insert(nei);
241  }
242  }
243  }
244 
245  if (k == 0)
246  {
247  continue;
248  }
249 
250  if (const auto cache_it = cache.find(cache_key); cache_it != cache.end())
251  {
252  IGRAPH_CHECK(igraph_vector_int_update(current_component_p, cache_it->second));
253  }
254  else
255  {
256  igraph_t subgraph;
257  igraph_vs_t subgraph_vertices = igraph_vss_vector(current_hood_p);
258  IGRAPH_FINALLY(igraph_vs_destroy, &subgraph_vertices);
259  igraph_vector_int_t vertex_map;
260  IGRAPH_VECTOR_INT_INIT_FINALLY(&vertex_map, igraph_vector_int_size(current_hood_p));
261  IGRAPH_CHECK(igraph_induced_subgraph_map(graph, &subgraph, subgraph_vertices, IGRAPH_SUBGRAPH_CREATE_FROM_SCRATCH, nullptr, &vertex_map));
262  IGRAPH_FINALLY(igraph_destroy, &subgraph);
263 
264  igraph_vector_int_t membership, csize;
265  IGRAPH_VECTOR_INT_INIT_FINALLY(&membership, 0);
266  IGRAPH_VECTOR_INT_INIT_FINALLY(&csize, 0);
267  IGRAPH_CHECK(igraph_connected_components(&subgraph, &membership, &csize, nullptr, IGRAPH_STRONG));
268 
269  u32 max_id = igraph_vector_int_which_max(&csize);
270  u32 num_subgraph_vertices = igraph_vcount(&subgraph);
271  for (i32 i = 0; i < num_subgraph_vertices; i++)
272  {
273  u32 cid = VECTOR(membership)[i];
274  if (cid == max_id)
275  {
276  IGRAPH_CHECK(igraph_vector_int_push_back(current_component_p, VECTOR(vertex_map)[i]));
277  }
278  }
279 
280  igraph_vs_destroy(&subgraph_vertices);
281  igraph_vector_int_destroy(&vertex_map);
282  igraph_vector_int_destroy(&membership);
283  igraph_vector_int_destroy(&csize);
284  igraph_destroy(&subgraph);
285  IGRAPH_FINALLY_CLEAN(5);
286 
287  igraph_vector_int_t* cache_tmp = new igraph_vector_int_t;
288  IGRAPH_CHECK(igraph_vector_int_init(cache_tmp, 0)); // cleanup handled by caller
289  IGRAPH_CHECK(igraph_vector_int_update(cache_tmp, current_component_p));
290  cache[cache_key] = cache_tmp;
291  }
292  }
293  else
294  {
295  if (previous_size == current_size)
296  {
297  IGRAPH_CHECK(igraph_vector_int_update(in_set, previous_component_p));
298  IGRAPH_CHECK(igraph_vector_int_update(out_set, current_component_p));
299  }
300 
301  break;
302  }
303  }
304 
305  igraph_vector_int_destroy(current_hood_p);
306  igraph_vector_int_destroy(previous_hood_p);
307  igraph_vector_int_destroy(current_component_p);
308  igraph_vector_int_destroy(previous_component_p);
309  igraph_vector_int_destroy(&tmp);
310  IGRAPH_FREE(added);
311  IGRAPH_FINALLY_CLEAN(6);
312 
313  return IGRAPH_SUCCESS;
314  }
315  } // namespace
316 
317  Result<std::vector<CipherCandidate>> CipherCandidate::detect(Netlist* nl, const std::vector<DetectionConfiguration>& configs, u32 min_state_size, const std::vector<Gate*>& start_ffs)
318  {
319  if (nl == nullptr)
320  {
321  return ERR("netlist is a nullptr");
322  }
323 
324  log_info("hawkeye", "start detecting state register candidates...");
325  auto start = std::chrono::system_clock::now();
326 
327  const user_feedback::ProgressScope progress("hawkeye: detecting candidates …");
328 
329  const auto nl_dec = NetlistTraversalDecorator(*nl);
330  std::map<Gate*, std::set<Gate*>> ff_map;
331  std::unordered_map<const Net*, std::set<Gate*>> cache = {};
332  const auto start_gates = nl->get_gates([](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::ff); });
333  for (auto* sg : start_gates)
334  {
335  if (const auto res = nl_dec.get_next_matching_gates(
336  sg, true, [](const Gate* g) { return g->get_type()->has_property(GateTypeProperty::ff); }, false, continue_through_exit_ep, continue_through_entry_ep);
337  res.is_ok())
338  {
339  ff_map[sg] = res.get();
340  }
341  else
342  {
343  return ERR(res.get_error());
344  }
345  }
346 
347  auto res = graph_algorithm::NetlistGraph::from_netlist_no_edges(nl, start_gates);
348  if (res.is_error())
349  {
350  return ERR(res.get_error());
351  }
352  auto base_graph = res.get();
353 
354  const auto start_vertices_res = base_graph->get_vertices_from_gates(start_ffs.empty() ? start_gates : start_ffs);
355  if (start_vertices_res.is_error())
356  {
357  return ERR(start_vertices_res.get_error());
358  }
359  auto start_vertices = start_vertices_res.get();
360 
361  // A candidate is keyed by the gate IDs of its registers, so that the same candidate found by several
362  // configurations is only kept once and the order does not depend on where the gates are allocated.
363  const auto sorted_ids = [](const std::set<Gate*>& gates) {
364  std::vector<u32> res;
365  res.reserve(gates.size());
366  for (const auto* g : gates)
367  {
368  res.push_back(g->get_id());
369  }
370  std::sort(res.begin(), res.end());
371  return res;
372  };
373 
374  std::map<std::pair<std::vector<u32>, std::vector<u32>>, CipherCandidate> unique_candidates;
375  for (const auto& config : configs)
376  {
377  auto tmp_graph_res = base_graph->copy();
378  if (tmp_graph_res.is_error())
379  {
380  return ERR(tmp_graph_res.get_error());
381  }
382  auto tmp_graph = tmp_graph_res.get();
383 
384  std::map<Gate*, std::set<Gate*>> filtered_map;
385  if (config.control == DetectionConfiguration::Control::CHECK_FF)
386  {
387  filtered_map = std::move(ff_map);
388  if (const auto edge_res = tmp_graph->add_edges(ff_map); edge_res.is_error())
389  {
390  return ERR(edge_res.get_error());
391  }
392  }
393  else if (config.control == DetectionConfiguration::Control::CHECK_TYPE)
394  {
395  std::map<const GateType*, std::set<const GateType*>> allowed_gate_type_map;
396  const auto* gl = nl->get_gate_library();
397  for (const auto& gt_list : config.equivalent_types)
398  {
399  std::set<const GateType*> types;
400  for (const auto& gt_name : gt_list)
401  {
402  types.insert(gl->get_gate_type_by_name(gt_name));
403  }
404 
405  for (const auto* gt : types)
406  {
407  allowed_gate_type_map[gt] = types;
408  }
409  }
410 
411  for (const auto& [src, dsts] : ff_map)
412  {
413  for (auto* dst : dsts)
414  {
415  const auto* src_type = src->get_type();
416  const auto* dst_type = dst->get_type();
417  if (src_type != dst_type)
418  {
419  if (const auto src_it = allowed_gate_type_map.find(src_type); src_it != allowed_gate_type_map.end())
420  {
421  const auto& allowed_gates = std::get<1>(*src_it);
422  if (allowed_gates.find(dst_type) == allowed_gates.end())
423  {
424  continue;
425  }
426  }
427  else
428  {
429  continue;
430  }
431  }
432 
433  filtered_map[src].insert(dst);
434  }
435  }
436  }
437  else if (config.control == DetectionConfiguration::Control::CHECK_NETS)
438  {
439  std::unordered_map<const Gate*, std::map<PinType, const Net*>> control_map;
440  for (const auto* gate : start_gates)
441  {
442  control_map[gate] = std::map<PinType, const Net*>();
443 
444  for (const auto& ep : gate->get_fan_in_endpoints())
445  {
446  if (auto pin_type = ep->get_pin()->get_type(); control_types.find(pin_type) != control_types.end())
447  {
448  control_map[gate][pin_type] = ep->get_net();
449  }
450  }
451  }
452 
453  for (const auto& [src, dsts] : ff_map)
454  {
455  for (auto* dst : dsts)
456  {
457  if (control_map.at(src) != control_map.at(dst))
458  {
459  continue;
460  }
461 
462  filtered_map[src].insert(dst);
463  }
464  }
465  }
466  else if (config.control == DetectionConfiguration::Control::CHECK_PINS)
467  {
468  std::unordered_map<const Gate*, std::set<PinType>> control_map;
469  for (const auto* gate : start_gates)
470  {
471  control_map[gate] = std::set<PinType>();
472 
473  for (const auto& ep : gate->get_fan_in_endpoints())
474  {
475  auto sources = ep->get_net()->get_sources();
476  if (sources.size() != 1)
477  {
478  continue;
479  }
480  if (sources.at(0)->get_gate()->is_gnd_gate() || sources.at(0)->get_gate()->is_vcc_gate())
481  {
482  continue;
483  }
484 
485  if (auto pin_type = ep->get_pin()->get_type(); control_types.find(pin_type) != control_types.end())
486  {
487  control_map[gate].insert(pin_type);
488  }
489  }
490  }
491 
492  for (const auto& [src, dsts] : ff_map)
493  {
494  for (auto* dst : dsts)
495  {
496  // if (src->get_type() != dst->get_type())
497  // {
498  // continue;
499  // }
500 
501  if (control_map.at(src) != control_map.at(dst))
502  {
503  continue;
504  }
505 
506  filtered_map[src].insert(dst);
507  }
508  }
509  }
510 
511  if (const auto edge_res = tmp_graph->add_edges(filtered_map); edge_res.is_error())
512  {
513  return ERR(edge_res.get_error());
514  }
515 
516  igraph_vector_int_t in_set, out_set;
517  if (const auto res = igraph_vector_int_init(&in_set, 0); res != IGRAPH_SUCCESS)
518  {
519  return ERR(igraph_strerror(res));
520  }
521 
522  if (const auto res = igraph_vector_int_init(&out_set, 0); res != IGRAPH_SUCCESS)
523  {
524  igraph_vector_int_destroy(&in_set);
525  return ERR(igraph_strerror(res));
526  }
527 
528  std::set<GraphCandidate> graph_candidates;
529 
530  if (config.components == DetectionConfiguration::Components::NONE)
531  {
532  for (const auto v : start_vertices)
533  {
534  igraph_vector_int_clear(&in_set);
535  igraph_vector_int_clear(&out_set);
536 
537  if (const auto res = get_saturating_neighborhoods(tmp_graph->get_graph(), &in_set, &out_set, v, config.timeout); res != IGRAPH_SUCCESS)
538  {
539  igraph_vector_int_destroy(&in_set);
540  igraph_vector_int_destroy(&out_set);
541  return ERR(igraph_strerror(res));
542  }
543 
544  u32 size = igraph_vector_int_size(&out_set);
545  if (size <= config.min_register_size)
546  {
547  continue;
548  }
549 
550  GraphCandidate c;
551  c.size = size;
552  for (u32 i = 0; i < igraph_vector_int_size(&in_set); i++)
553  {
554  c.in_reg.insert(VECTOR(in_set)[i]);
555  }
556  for (u32 i = 0; i < igraph_vector_int_size(&out_set); i++)
557  {
558  c.out_reg.insert(VECTOR(out_set)[i]);
559  }
560  graph_candidates.insert(c);
561  }
562  }
563  else if (config.components == DetectionConfiguration::Components::CHECK_SCC)
564  {
565  std::map<std::set<u32>, igraph_vector_int_t*> scc_cache;
566 
567  for (const auto v : start_vertices)
568  {
569  igraph_vector_int_clear(&in_set);
570  igraph_vector_int_clear(&out_set);
571 
572  if (const auto res = get_saturating_neighborhoods_scc(tmp_graph->get_graph(), &in_set, &out_set, v, config.timeout, scc_cache); res != IGRAPH_SUCCESS)
573  {
574  igraph_vector_int_destroy(&in_set);
575  igraph_vector_int_destroy(&out_set);
576  for (auto& [_, comp] : scc_cache)
577  {
578  igraph_vector_int_destroy(comp);
579  delete comp;
580  }
581  return ERR(igraph_strerror(res));
582  }
583 
584  u32 size = igraph_vector_int_size(&out_set);
585  if (size <= config.min_register_size)
586  {
587  continue;
588  }
589 
590  GraphCandidate c;
591  c.size = size;
592  for (u32 i = 0; i < igraph_vector_int_size(&in_set); i++)
593  {
594  c.in_reg.insert(VECTOR(in_set)[i]);
595  }
596  for (u32 i = 0; i < igraph_vector_int_size(&out_set); i++)
597  {
598  c.out_reg.insert(VECTOR(out_set)[i]);
599  }
600  graph_candidates.insert(c);
601  }
602 
603  for (auto& [_, comp] : scc_cache)
604  {
605  igraph_vector_int_destroy(comp);
606  delete comp;
607  }
608  }
609 
610  igraph_vector_int_destroy(&in_set);
611  igraph_vector_int_destroy(&out_set);
612 
613  for (const auto& gc : graph_candidates)
614  {
615  std::set<Gate*> out_reg;
616 
617  if (auto out_reg_res = tmp_graph->get_gates_set_from_vertices(gc.out_reg); out_reg_res.is_ok())
618  {
619  out_reg = out_reg_res.get();
620  }
621  else
622  {
623  return ERR(out_reg_res.get_error());
624  }
625 
626  if (gc.in_reg == gc.out_reg)
627  {
628  auto key = std::make_pair(sorted_ids(out_reg), sorted_ids(out_reg));
629  unique_candidates.try_emplace(std::move(key), CipherCandidate(out_reg));
630  }
631  else
632  {
633  std::set<Gate*> in_reg;
634  if (auto in_reg_res = tmp_graph->get_gates_set_from_vertices(gc.in_reg); in_reg_res.is_ok())
635  {
636  in_reg = in_reg_res.get();
637  auto key = std::make_pair(sorted_ids(in_reg), sorted_ids(out_reg));
638  unique_candidates.try_emplace(std::move(key), CipherCandidate(in_reg, out_reg));
639  }
640  else
641  {
642  return ERR(in_reg_res.get_error());
643  }
644  }
645  }
646  }
647 
648  // order the candidates by size, as the reduction below relies on a candidate being visited before the
649  // smaller candidates that it may contain
650  std::vector<CipherCandidate> candidates;
651  candidates.reserve(unique_candidates.size());
652  for (auto& [_, candidate] : unique_candidates)
653  {
654  candidates.push_back(std::move(candidate));
655  }
656  std::sort(candidates.begin(), candidates.end(), [](const CipherCandidate& lhs, const CipherCandidate& rhs) { return lhs < rhs; });
657 
658  // Discard the candidates that are too small to hold a cryptographic state, as well as those whose output
659  // register fully contains that of another candidate, keeping the smaller and hence more specific one.
660  const auto by_id = [](const Gate* lhs, const Gate* rhs) { return lhs->get_id() < rhs->get_id(); };
661  std::vector<bool> discard(candidates.size(), false);
662  for (u32 i = 0; i < candidates.size(); i++)
663  {
664  if (candidates.at(i).get_size() < min_state_size)
665  {
666  discard[i] = true;
667  continue;
668  }
669 
670  const auto& outer = candidates.at(i).get_output_reg();
671  for (u32 j = i + 1; j < candidates.size(); j++)
672  {
673  const auto& inner = candidates.at(j).get_output_reg();
674  if (std::includes(outer.begin(), outer.end(), inner.begin(), inner.end(), by_id))
675  {
676  discard[i] = true;
677  break;
678  }
679  }
680  }
681 
682  u32 kept = 0;
683  for (u32 i = 0; i < candidates.size(); i++)
684  {
685  if (discard[i])
686  {
687  continue;
688  }
689 
690  // moving a candidate onto itself is not guaranteed to leave it intact
691  if (kept != i)
692  {
693  candidates[kept] = std::move(candidates[i]);
694  }
695  kept++;
696  }
697  candidates.resize(kept);
698 
699  auto duration_in_seconds = std::chrono::duration<double>(std::chrono::system_clock::now() - start).count();
700  if (candidates.size() == 1)
701  {
702  log_info("hawkeye", "detected {} state register candidate in {} seconds", candidates.size(), duration_in_seconds);
703  }
704  else
705  {
706  log_info("hawkeye", "detected {} state register candidates in {} seconds", candidates.size(), duration_in_seconds);
707  }
708 
709  return OK(std::move(candidates));
710  }
711  } // namespace hawkeye
712 
713  template<>
714  std::map<hawkeye::DetectionConfiguration::Control, std::string> EnumStrings<hawkeye::DetectionConfiguration::Control>::data = {
719 
720  template<>
721  std::map<hawkeye::DetectionConfiguration::Components, std::string> EnumStrings<hawkeye::DetectionConfiguration::Components>::data = {
724 } // namespace hal
std::set< u32 > out_reg
std::set< u32 > in_reg
u32 size
This file contains the struct for configuring HAWKEYE's candidate search, see CipherCandidate::detect...
This file contains the class that holds all information on a candidate for a symmetric cryptographic ...
Definition: gate.h:58
GateType * get_type() const
Definition: gate.cpp:125
u32 get_id() const
Definition: gate.cpp:95
const std::vector< Gate * > & get_gates() const
Definition: netlist.cpp:206
const GateLibrary * get_gate_library() const
Definition: netlist.cpp:134
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 candidate for a symmetric cryptographic implementation within a netlist.
static Result< std::vector< CipherCandidate > > detect(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 SPN, Feistel, and ARX implementations within...
uint32_t u32
Definition: defines.h:41
int32_t i32
Definition: defines.h:36
#define log_info(channel,...)
Definition: log.h:70
#define ERR(message)
Definition: result.h:60
#define OK(...)
Definition: result.h:56
Definition: defines.h:45
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.