HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
python_bindings.cpp
Go to the documentation of this file.
2 
7 #include "hawkeye/sbox_lookup.h"
8 #include "pybind11/operators.h"
9 #include "pybind11/pybind11.h"
10 #include "pybind11/stl.h"
11 #include "pybind11/stl_bind.h"
12 
13 namespace py = pybind11;
14 
15 namespace hal
16 {
17 
18  // the name in PYBIND11_MODULE/PYBIND11_PLUGIN *MUST* match the filename of the output library (without extension),
19  // otherwise you will get "ImportError: dynamic module does not define module export function" when importing the module
20 
21 #ifdef PYBIND11_MODULE
22  PYBIND11_MODULE(hawkeye, m)
23  {
24  m.doc() = "Automated tool to locate arbitrary symmetric cryptographic implementations in gate-level netlists.";
25 #else
26  PYBIND11_PLUGIN(hawkeye)
27  {
28  py::module m("hawkeye", "Automated tool to locate arbitrary symmetric cryptographic implementations in gate-level netlists.");
29 #endif // ifdef PYBIND11_MODULE
30 
31  py::class_<HawkeyePlugin, RawPtrWrapper<HawkeyePlugin>, BasePluginInterface> py_hawkeye_plugin(
32  m, "HawkeyePlugin", R"(This class provides an interface to integrate the HAWKEYE tool as a plugin within the HAL framework.)");
33 
34  py_hawkeye_plugin.def_property_readonly("name", &HawkeyePlugin::get_name, R"(
35  The name of the plugin.
36 
37  :type: str
38  )");
39 
40  py_hawkeye_plugin.def("get_name", &HawkeyePlugin::get_name, R"(
41  Get the name of the plugin.
42 
43  :returns: The name of the plugin.
44  :rtype: str
45  )");
46 
47  py_hawkeye_plugin.def_property_readonly("version", &HawkeyePlugin::get_version, R"(
48  The version of the plugin.
49 
50  :type: str
51  )");
52 
53  py_hawkeye_plugin.def("get_version", &HawkeyePlugin::get_version, R"(
54  Get the version of the plugin.
55 
56  :returns: The version of the plugin.
57  :rtype: str
58  )");
59 
60  py_hawkeye_plugin.def_property_readonly("description", &HawkeyePlugin::get_description, R"(
61  The description of the plugin.
62 
63  :type: str
64  )");
65 
66  py_hawkeye_plugin.def("get_description", &HawkeyePlugin::get_description, R"(
67  Get the description of the plugin.
68 
69  :returns: The description of the plugin.
70  :rtype: str
71  )");
72 
73  py_hawkeye_plugin.def_property_readonly("dependencies", &HawkeyePlugin::get_dependencies, R"(
74  A set of plugin names that this plugin depends on.
75 
76  :type: set[str]
77  )");
78 
79  py_hawkeye_plugin.def("get_dependencies", &HawkeyePlugin::get_dependencies, R"(
80  Get a set of plugin names that this plugin depends on.
81 
82  :returns: A set of plugin names that this plugin depends on.
83  :rtype: set[str]
84  )");
85 
86  py::class_<hawkeye::SBoxDatabase, RawPtrWrapper<hawkeye::SBoxDatabase>> py_hawkeye_sbox_database(m, "SBoxDatabase", R"(
87  This class holds and manages known S-boxes and allows to perform efficient S-box lookups in the database.
88  )");
89 
90  py_hawkeye_sbox_database.def(py::init<>(), R"(
91  Construct an empty S-box database.
92  )");
93 
94  py_hawkeye_sbox_database.def(py::init<const std::map<std::string, std::vector<u8>>&>(), py::arg("sboxes"), R"(
95  Construct an S-box database from the given S-boxes.
96 
97  :param dict[str,list[int]] sboxes: A dict from S-box name to the respective S-box.
98  )");
99 
100  py_hawkeye_sbox_database.def_static(
101  "from_file",
102  [](const std::filesystem::path& file_path) -> std::optional<hawkeye::SBoxDatabase> {
103  auto res = hawkeye::SBoxDatabase::from_file(file_path);
104  if (res.is_ok())
105  {
106  return res.get();
107  }
108  else
109  {
110  log_error("python_context", "{}", res.get_error().get());
111  return std::nullopt;
112  }
113  },
114  py::arg("file_path"),
115  R"(
116  Construct an S-box database from file.
117 
118  :param pathlib.Path file_path: The path from which to load the S-box database file.
119  :returns: The S-box database on success, ``None`` otherwise.
120  :rtype: hawkeye.SBoxDatabase or None
121  )");
122 
123  py_hawkeye_sbox_database.def_static("compute_linear_representative", &hawkeye::SBoxDatabase::compute_linear_representative, py::arg("sbox"), R"(
124  Compute the linear representative of the given S-box.
125 
126  :param list[int] sbox: The S-box.
127  :returns: The linear representative.
128  :rtype: list[int]
129  )");
130 
131  py_hawkeye_sbox_database.def(
132  "add",
133  [](hawkeye::SBoxDatabase& self, const std::string& name, const std::vector<u8>& sbox) -> bool {
134  auto res = self.add(name, sbox);
135  if (res.is_ok())
136  {
137  return true;
138  }
139  else
140  {
141  log_error("python_context", "{}", res.get_error().get());
142  return false;
143  }
144  },
145  py::arg("name"),
146  py::arg("sbox"),
147  R"(
148  Add an S-box to the database.
149 
150  :param str name: The name of the S-box.
151  :patam list[int] sbox: The S-box.
152  :returns: ``True`` on success, ``False`` otherwise.
153  :rtype: bool
154  )");
155 
156  py_hawkeye_sbox_database.def(
157  "add",
158  [](hawkeye::SBoxDatabase& self, const std::map<std::string, std::vector<u8>>& sboxes) -> bool {
159  auto res = self.add(sboxes);
160  if (res.is_ok())
161  {
162  return true;
163  }
164  else
165  {
166  log_error("python_context", "{}", res.get_error().get());
167  return false;
168  }
169  },
170  py::arg("sboxes"),
171  R"(
172  Add multiple S-boxes to the database.
173 
174  :param dict[str,list[int]] sboxes: A dict from S-box name to the respective S-box.
175  :returns: ``True`` on success, ``False`` otherwise.
176  :rtype: bool
177  )");
178 
179  py_hawkeye_sbox_database.def(
180  "load",
181  [](hawkeye::SBoxDatabase& self, const std::filesystem::path& file_path, bool overwrite = false) -> bool {
182  auto res = self.load(file_path, overwrite);
183  if (res.is_ok())
184  {
185  return true;
186  }
187  else
188  {
189  log_error("python_context", "{}", res.get_error().get());
190  return false;
191  }
192  },
193  py::arg("file_path"),
194  py::arg("overwrite") = false,
195  R"(
196  Load S-boxes from a file and add them to the existing database.
197 
198  :param pathlib.Path file_path: The path from which to load the S-box database file.
199  :param bool overwrite: Set ``True`` to overwrite existing database, ``False`` otherwise. Defaults to ``False``.
200  :returns: ``True`` on success, ``False`` otherwise.
201  :rtype: bool
202  )");
203 
204  py_hawkeye_sbox_database.def(
205  "store",
206  [](const hawkeye::SBoxDatabase& self, const std::filesystem::path& file_path) -> bool {
207  auto res = self.store(file_path);
208  if (res.is_ok())
209  {
210  return true;
211  }
212  else
213  {
214  log_error("python_context", "{}", res.get_error().get());
215  return false;
216  }
217  },
218  py::arg("file_path"),
219  R"(
220  Store the S-box database to a database file.
221 
222  :param pathlib.Path file_path: The path to where to store the S-box database file.
223  :returns: ``True`` on success, ``False`` otherwise.
224  :rtype: bool
225  )");
226 
227  py_hawkeye_sbox_database.def(
228  "lookup",
229  [](const hawkeye::SBoxDatabase& self, const std::vector<u8>& sbox) -> std::optional<std::string> {
230  auto res = self.lookup(sbox);
231  if (res.is_ok())
232  {
233  return res.get();
234  }
235  else
236  {
237  log_error("python_context", "{}", res.get_error().get());
238  return std::nullopt;
239  }
240  },
241  py::arg("sbox"),
242  R"(
243  Attempt to look up an S-box in the database.
244 
245  :param list[int] sbox: The S-box to look for.
246  :returns: The S-box name on success, ``None`` otherwise.
247  :rtype: str or None
248  )");
249 
250  py_hawkeye_sbox_database.def("print", &hawkeye::SBoxDatabase::print, R"(
251  Print the database.
252  )");
253 
254  py::class_<hawkeye::DetectionConfiguration, RawPtrWrapper<hawkeye::DetectionConfiguration>> py_hawkeye_detection_configuration(
255  m, "DetectionConfiguration", R"(This class holds important parameters that configure the candidate search of HAWKEYE.)");
256 
257  py_hawkeye_detection_configuration.def(py::init<>(), R"(
258  Constructs a default DetectionConfiguration.
259  )");
260 
261  py::enum_<hawkeye::DetectionConfiguration::Control> py_hawkeye_detection_configuration_control(
262  py_hawkeye_detection_configuration,
263  "Control",
264  R"(This enum specifies the checks that are to be performed on the flip-flops of the netlist to determine whether there should be an edge between two flip-flops or not.)");
265 
266  py_hawkeye_detection_configuration_control
267  .value("CHECK_FF",
269  R"(If two flip-flops ``ff1`` and ``ff2`` are connected through combinational logic, an edge is added such that ``(ff1,ff2)`` is part of the graph.)")
270  .value("CHECK_TYPE",
272  R"(If two flip-flops ``ff1`` and ``ff2`` are connected through combinational logic and are of the same gate type, an edge is added such that ``(ff1,ff2)`` is part of the graph.)")
273  .value(
274  "CHECK_PINS",
276  R"(If two flip-flops ``ff1`` and ``ff2`` are connected through combinational logic and are controlled through the same input pins, an edge is added such that ``(ff1,ff2)`` is part of the graph.)")
277  .value(
278  "CHECK_NETS",
280  R"(If two flip-flops ``ff1`` and ``ff2`` are connected through combinational logic and are controlled through the same input nets, an edge is added such that ``(ff1,ff2)`` is part of the graph.)")
281  .export_values();
282 
283  py_hawkeye_detection_configuration.def_readwrite("control", &hawkeye::DetectionConfiguration::control, R"(
284  Checks to be performed on flip-flop control inputs during candidate search.
285 
286  :type: hawkeye.DetectionConfiguration.Control
287  )");
288 
289  py::enum_<hawkeye::DetectionConfiguration::Components> py_hawkeye_detection_configuration_components(py_hawkeye_detection_configuration,
290  "Components",
291  R"(
292  This enum specifies whether SCC detection should be used to refine the results of neighborhood discovery. If SCC detection is used, the exploration only stops if the size of the largest discovered SCC saturates. Specifically, it does no longer require the size of the entire neighborhood to saturate.
293  )");
294 
295  py_hawkeye_detection_configuration_components
296  .value("NONE", hawkeye::DetectionConfiguration::Components::NONE, R"(Do not use SCC detection and instead resort to the simple neighborhood discovery algorithm.)")
297  .value("CHECK_SCC", hawkeye::DetectionConfiguration::Components::CHECK_SCC, R"(Use SCC detection within the currently explored neighborhood of a start flip-flop.)")
298  .export_values();
299 
300  py_hawkeye_detection_configuration.def_readwrite("components", &hawkeye::DetectionConfiguration::components, R"(
301  Determines whether to use SCC detection as part of neighborhood discovery.
302 
303  :type: hawkeye.DetectionConfiguration.Components
304  )");
305 
306  py_hawkeye_detection_configuration.def_readwrite("equivalent_types", &hawkeye::DetectionConfiguration::equivalent_types, R"(
307  A list of a list of gate types that are treated as identical types by the candidate search, i.e., when checking equality of the types of two gates that are different but declared equivalent, ``True`` is returned.
308 
309  :type: list[list[str]]
310  )");
311 
312  py_hawkeye_detection_configuration.def_readwrite("timeout", &hawkeye::DetectionConfiguration::timeout, R"(
313  Neighborhood discovery iteration timeout.
314 
315  :type: int
316  )");
317 
318  py_hawkeye_detection_configuration.def_readwrite("min_register_size", &hawkeye::DetectionConfiguration::min_register_size, R"(
319  Minimum number of flip-flops for a register candidate to be created.
320 
321  :type: int
322  )");
323 
324  py::class_<hawkeye::RegisterCandidate, RawPtrWrapper<hawkeye::RegisterCandidate>> py_hawkeye_register_candidate(m, "RegisterCandidate", R"(
325  This class holds all information belonging to a register candidate discovered by HAWKEYE's candidate search and makes these information accessible through getters.
326  )");
327 
328  py_hawkeye_register_candidate.def(py::init<>(), R"(Default constructor for ``RegisterCandidate``.)");
329 
330  py_hawkeye_register_candidate.def(py::init<const std::set<Gate*>&>(), py::arg("round_reg"), R"(
331  Construct a state register candidate from the state register of a round-based implementation.
332 
333  :param set[hal_py.Gate] round_reg: The state register.
334  )");
335 
336  py_hawkeye_register_candidate.def(py::init<const std::set<Gate*>&, const std::set<Gate*>&>(), py::arg("in_reg"), py::arg("out_reg"), R"(
337  Construct a state register candidate from the input and output registers from one round of a pipelined implementation.
338 
339  :param set[hal_py.Gate] in_reg: The input register.
340  :param set[hal_py.Gate] out_reg: The output register.
341  )");
342 
343  py_hawkeye_register_candidate.def("get_netlist", &hawkeye::RegisterCandidate::get_netlist, R"(
344  Get the netlist associated with the candidate.
345 
346  :returns: The netlist of the candidate.
347  :rtype: hal_py.Netlist
348  )");
349 
350  py_hawkeye_register_candidate.def("get_size", &hawkeye::RegisterCandidate::get_size, R"(
351  Get the size of the candidate, i.e., the width of its registers.
352 
353  :returns: The size of the candidate.
354  :rtype: int
355  )");
356 
357  py_hawkeye_register_candidate.def("is_round_based", &hawkeye::RegisterCandidate::is_round_based, R"(
358  Check if the candidate is round-based, i.e., input and output register are the same.
359 
360  :returns: ``True`` if the candidate is round-based, ``False`` otherwise.
361  :rtype: bool
362  )");
363 
364  py_hawkeye_register_candidate.def("get_input_reg", &hawkeye::RegisterCandidate::get_input_reg, R"(
365  Get the candidate's input register.
366 
367  :returns: The input register of the candidate.
368  :rtype: set[hal_py.Gate]
369  )");
370 
371  py_hawkeye_register_candidate.def("get_output_reg", &hawkeye::RegisterCandidate::get_output_reg, R"(
372  Get the candidate's output register.
373 
374  :returns: The output register of the candidate.
375  :rtype: set[hal_py.Gate]
376  )");
377 
378  py::class_<hawkeye::RoundCandidate, RawPtrWrapper<hawkeye::RoundCandidate>> py_hawkeye_round_candidate(m, "RoundCandidate", R"(
379  This class holds all information belonging to a round candidate. Round candidates are constructed from register candidates by copying the sub-circuit consisting of the input and (if pipelined) output registers as well as the next-state/round-function logic in between these registers.
380  For round-based implementations, commonly only a single register exists that acts as an input and output register at the same time.
381  In such cases, this register is considered to be the input register of the round function and an exact copy of the register will be appended to the round function outputs so that input and output register are guaranteed to be distinct.
382  )");
383 
384  py_hawkeye_round_candidate.def(py::init<>(), R"(Default constructor for ``RoundCandidate``.)");
385 
386  py_hawkeye_round_candidate.def_static(
387  "from_register_candidate",
388  [](hawkeye::RegisterCandidate* candidate) -> std::unique_ptr<hawkeye::RoundCandidate> {
390  if (res.is_ok())
391  {
392  return res.get();
393  }
394  else
395  {
396  log_error("python_context", "{}", res.get_error().get());
397  return nullptr;
398  }
399  },
400  py::arg("candidate"),
401  R"(
402  Compute a round candidate from a previously identified register candidate.
403  The netlist of this candidate will be a partial copy of the original netlist, comprising only the gates belonging to the registers and the logic computing the next state.
404  In case of a round-based implementation, the output register will be a copy of the input register.
405  All data structures of the round candidate will be initialized in the process.
406 
407  :param hawkeye.RegisterCandidate candidate: The register candidate.
408  :returns: The round candidate on success, ``None`` otherwise.
409  :rtype: hawkeye.RoundCandidate or None
410  )");
411 
412  py_hawkeye_round_candidate.def("get_netlist", &hawkeye::RoundCandidate::get_netlist, R"(
413  Get the netlist of the round candidate. The netlist is a partial copy of the netlist of the register candidate.
414 
415  :returns: The netlist of the candidate.
416  :rtype: hal_py.Netlist
417  )");
418 
419  py_hawkeye_round_candidate.def("get_graph", &hawkeye::RoundCandidate::get_graph, R"(
420  Get the netlist graph of the round candidate.
421 
422  :returns: The netlist graph of the candidate.
423  :rtype: graph_algorithm.NetlistGraph
424  )");
425 
426  py_hawkeye_round_candidate.def("get_size", &hawkeye::RoundCandidate::get_size, R"(
427  Get the size of the candidate, i.e., the width of its registers.
428 
429  :returns: The size of the candidate.
430  :rtype: int
431  )");
432 
433  py_hawkeye_round_candidate.def("get_input_reg", &hawkeye::RoundCandidate::get_input_reg, R"(
434  Get the candidate's input register.
435 
436  :returns: The input register of the candidate.
437  :rtype: set[hal_py.Gate]
438  )");
439 
440  py_hawkeye_round_candidate.def("get_output_reg", &hawkeye::RoundCandidate::get_output_reg, R"(
441  Get the candidate's output register.
442 
443  :returns: The output register of the candidate.
444  :rtype: set[hal_py.Gate]
445  )");
446 
447  py_hawkeye_round_candidate.def("get_state_logic", &hawkeye::RoundCandidate::get_state_logic, R"(
448  Get the candidate's combinational logic computing the next state.
449 
450  :returns: The state logic of the candidate.
451  :rtype: set[hal_py.Gate]
452  )");
453 
454  py_hawkeye_round_candidate.def("get_state_inputs", &hawkeye::RoundCandidate::get_state_inputs, R"(
455  Get the candidate's state inputs to the logic computing the next state.
456 
457  :returns: The state inputs of the candidate.
458  :rtype: set[hal_py.Net]
459  )");
460 
461  py_hawkeye_round_candidate.def("get_control_inputs", &hawkeye::RoundCandidate::get_control_inputs, R"(
462  Get the candidate's control inputs to the logic computing the next state.
463 
464  :returns: The control inputs of the candidate.
465  :rtype: set[hal_py.Net]
466  )");
467 
468  py_hawkeye_round_candidate.def("get_other_inputs", &hawkeye::RoundCandidate::get_other_inputs, R"(
469  Get the candidate's other inputs to the logic computing the next state.
470 
471  :returns: The other inputs of the candidate.
472  :rtype: set[hal_py.Net]
473  )");
474 
475  py_hawkeye_round_candidate.def("get_state_outputs", &hawkeye::RoundCandidate::get_state_outputs, R"(
476  Get the candidate's state outputs from the logic computing the next state.
477 
478  :returns: The state outputs of the candidate.
479  :rtype: set[hal_py.Net]
480  )");
481 
482  py_hawkeye_round_candidate.def("get_input_ffs_of_gate", &hawkeye::RoundCandidate::get_input_ffs_of_gate, R"(
483  Get a dict from each combinational gate of the round function to all the input flip-flops it depends on.
484 
485  :returns: A dict from gates to sets of input flip-flops.
486  :rtype: dict[hal_py.Gate,set[hal_py.Gate]]
487  )");
488 
489  py_hawkeye_round_candidate.def("get_longest_distance_to_gate", &hawkeye::RoundCandidate::get_longest_distance_to_gate, R"(
490  Get a dict from an integer distance to all gates that are reachable within at most that distance when starting at any input flip-flop.
491 
492  :returns: A dict from longest distance to a set of gates being reachable in at most that distance.
493  :rtype: dict[int,set[hal_py.Gate]]
494  )");
495 
496  m.def(
497  "detect_candidates",
498  [](Netlist* nl, const std::vector<hawkeye::DetectionConfiguration>& configs, u32 min_state_size = 40, const std::vector<Gate*>& start_ffs = {})
499  -> std::optional<std::vector<hawkeye::RegisterCandidate>> {
500  auto res = hawkeye::detect_candidates(nl, configs, min_state_size, start_ffs);
501  if (res.is_ok())
502  {
503  return res.get();
504  }
505  else
506  {
507  log_error("python_context", "cannot detect crypto candidates:\n{}", res.get_error().get());
508  return std::nullopt;
509  }
510  },
511  py::arg("nl"),
512  py::arg("configs"),
513  py::arg("min_state_size") = 40,
514  py::arg("start_ffs") = std::vector<Gate*>(),
515  R"(
516  Attempt to locate candidates for symmetric cryptographic implementations within a gate-level netlist.
517  Search operates only on an abstraction of the netlist that contains only flip-flops as nodes and connections through combinational logic as edges.
518  The algorithm computes the k-neighborhood of each flip-flop for ``k = 1, ..., config.timeout`` and stops when the neighborhood size saturates.
519  Depending on the ``config``, additional criteria are used to narrow down the search space, see ``DetectionConfiguration.Control`` and ``DetectionConfiguration.Components`` for details.
520  When the neighborhood size saturates, a register candidate is created if the last neighborhood size is larger than ``config.min_register_size``.
521  After the candidates have been identified, they are reduced further to produce the final set of register candidates.
522  To this end, large candidates that fully contain a smaller candidate and candidates that are smaller than ``min_state_size`` are discarded.
523 
524  :param hal_py.Netlist nl: The netlist to operate on.
525  :param list[hawkeye.DetectionConfiguration] configs: The configurations of the detection approaches to be executed one after another on each start flip-flop.
526  :param int min_state_size: The minimum size of a register candidate to be considered a cryptographic state register. Defaults to ``40``.
527  :param list[hal_py.Gate] start_ffs: The flip-flops to analyze. Defaults to an empty list, i.e., all flip-flops in the netlist will be analyzed.
528  :returns: A list of candidates on success, ``None`` otherwise.
529  :rtype: list[hawkeye.RegisterCandidate] or None
530  )");
531 
532  py::class_<hawkeye::SBoxCandidate, RawPtrWrapper<hawkeye::SBoxCandidate>> py_hawkeye_sbox_candidate(
533  m,
534  "SBoxCandidate",
535  R"(This class stores all information related to an S-box candidate discovered within the round function of a round candidate, such as the ``RoundCandidate`` it belongs to, the connected component it is part of, and its input and output gates.)");
536 
537  py_hawkeye_sbox_candidate.def(py::init<>(), R"(
538  Default constructor for ``SBoxCandidate``.
539  )");
540 
541  py_hawkeye_sbox_candidate.def_readonly("m_candidate", &hawkeye::SBoxCandidate::m_candidate, R"(The ``RoundCandidate`` that the S-box candidate belongs to.)");
542 
543  py_hawkeye_sbox_candidate.def_readonly("m_component", &hawkeye::SBoxCandidate::m_component, R"(The gates of the component which the S-box candidate is part of.)");
544 
545  py_hawkeye_sbox_candidate.def_readonly("m_input_gates", &hawkeye::SBoxCandidate::m_input_gates, R"(The input gates of the S-box candidate (will be flip-flops).)");
546 
547  py_hawkeye_sbox_candidate.def_readonly(
548  "m_output_gates", &hawkeye::SBoxCandidate::m_output_gates, R"(The output gates of the S-box candidate (usually combinational logic that is input to the linear layer).)");
549 
550  m.def(
551  "locate_sboxes",
552  [](const hawkeye::RoundCandidate* candidate) -> std::optional<std::vector<hawkeye::SBoxCandidate>> {
553  auto res = hawkeye::locate_sboxes(candidate);
554  if (res.is_ok())
555  {
556  return res.get();
557  }
558  else
559  {
560  log_error("python_context", "cannot locate S-boxes:\n{}", res.get_error().get());
561  return std::nullopt;
562  }
563  },
564  py::arg("candidate"),
565  R"(
566  Try to locate S-box candidates within the combinational next-state logic of the round function candidate.
567  Computes an initial set of connected components within the round function extracted between the input and output register of the round candidate.
568  If these initial components are reasonably small and their input and output sizes match, construct S-box candidates for further analysis right away.
569  Otherwise, iteratively consider more combinational gates starting from the components' input gates and search for sub-components.
570  Create S-box candidates for these sub-components after determining the respective S-box output gates.
571 
572  :param hawkeye.RoundCandidate candidate: A round function candidate.
573  :returns: A list of S-box candidates on success, ``None`` otherwise.
574  :rtype: list[hawkeye.SBoxCandidate] or None
575  )");
576 
577  m.def(
578  "identify_sbox",
579  [](const hawkeye::SBoxCandidate& sbox_candidate, const hawkeye::SBoxDatabase& db) -> std::optional<std::string> {
580  auto res = hawkeye::identify_sbox(sbox_candidate, db);
581  if (res.is_ok())
582  {
583  return res.get();
584  }
585  else
586  {
587  log_error("python_context", "cannot identify S-box:\n{}", res.get_error().get());
588  return std::nullopt;
589  }
590  },
591  py::arg("sbox_candidate"),
592  py::arg("db"),
593  R"(
594  Try to identify an S-box candidate by matching it against a database of known S-boxes under affine equivalence.
595 
596  Note that a candidate which simply does not match any S-box of the database is not an error: in that case an empty string is returned. ``None`` is only returned if the candidate could not be analyzed at all.
597 
598  :param hawkeye.SBoxCandidate sbox_candidate: An S-box candidate.
599  :param hawkeye.SBoxDatabase db: A database of known S-boxes.
600  :returns: The name of the matching S-box, or an empty string if no S-box of the database matched. ``None`` on error.
601  :rtype: str or None
602  )");
603 
604 #ifndef PYBIND11_MODULE
605  return m.ptr();
606 #endif // PYBIND11_MODULE
607  }
608 } // namespace hal
This file contains the function for HAWKEYE's candidate search as well as a struct for configuring th...
std::string get_name() const override
Get the name of the plugin.
std::set< std::string > get_dependencies() const override
Get the plugin dependencies.
std::string get_description() const override
Get a short description of the plugin.
std::string get_version() const override
Get the version of the plugin.
A register candidate discovered by HAWKEYE.
Netlist * get_netlist() const
Get the netlist associated with the candidate.
bool is_round_based() const
Check if the candidate is round-based, i.e., input and output register are the same.
u32 get_size() const
Get the size of the candidate, i.e., the width of its registers.
const std::set< Gate * > & get_input_reg() const
Get the candidate's input register.
const std::set< Gate * > & get_output_reg() const
Get the candidate's output register.
A round candidate constructed from a previously discovered register candidate.
const std::set< Gate * > & get_state_logic() const
Get the candidate's combinational logic computing the next state.
const std::set< Net * > & get_other_inputs() const
Get the candidate's other inputs to the logic computing the next state.
const std::set< Net * > & get_control_inputs() const
Get the candidate's control inputs to the logic computing the next state.
u32 get_size() const
Get the size of the candidate, i.e., the width of its registers.
const std::map< Gate *, std::set< Gate * > > & get_input_ffs_of_gate() const
Get a map from each combinational gate of the round function to all the input flip-flops it depends o...
const std::set< Net * > & get_state_outputs() const
Get the candidate's state outputs from the logic computing the next state.
static Result< std::unique_ptr< RoundCandidate > > from_register_candidate(RegisterCandidate *candidate)
Compute a round candidate from a previously identified register candidate.
const std::map< u32, std::set< Gate * > > & get_longest_distance_to_gate() const
Get a map from an integer distance to all gates that are reachable within at most that distance when ...
const std::set< Gate * > & get_output_reg() const
Get the candidate's output register.
Netlist * get_netlist() const
Get the netlist of the round candidate. The netlist is a partial copy of the netlist of the register ...
graph_algorithm::NetlistGraph * get_graph() const
Get the netlist graph of the round candidate.
const std::set< Gate * > & get_input_reg() const
Get the candidate's input register.
const std::set< Net * > & get_state_inputs() const
Get the candidate's state inputs to the logic computing the next state.
An S-box candidate discovered within the round function of a round candidate.
Definition: sbox_lookup.h:58
std::set< Gate * > m_output_gates
The output gates of the S-box candidate (usually combinational logic that is input to the linear laye...
Definition: sbox_lookup.h:88
const RoundCandidate * m_candidate
The RoundCandidate that the S-box candidate belongs to.
Definition: sbox_lookup.h:73
std::vector< Gate * > m_component
The gates of the component which the S-box candidate is part of.
Definition: sbox_lookup.h:78
std::set< Gate * > m_input_gates
The input gates of the S-box candidate (will be flip-flops).
Definition: sbox_lookup.h:83
Database of known S-boxes.
Definition: sbox_database.h:50
static Result< SBoxDatabase > from_file(const std::filesystem::path &file_path)
Construct an S-box database from file.
void print() const
Print the database.
static std::vector< u8 > compute_linear_representative(const std::vector< u8 > &sbox)
Compute the linear representative of the given S-box.
uint32_t u32
Definition: defines.h:41
#define log_error(channel,...)
Definition: log.h:78
const Module * module(const Gate *g, const NodeBoxes &boxes)
Result< std::vector< SBoxCandidate > > locate_sboxes(const RoundCandidate *candidate)
Try to locate S-box candidates within the combinational next-state logic of the round function candid...
Definition: sbox_lookup.cpp:18
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.
Result< std::string > identify_sbox(const SBoxCandidate &sbox_candidate, const SBoxDatabase &db)
Try to identify an S-box candidate by matching it against a database of known S-boxes under affine eq...
Definition: defines.h:45
PYBIND11_PLUGIN(hal_py)
std::string name
This file contains all functions related to the HAL plugin API.
This file contains the class that holds all information on a round candidate.
This file contains the S-box database class that holds and manages known cryptographic S-boxes up to ...
This file contains a class that holds all information on an S-box candidate as well as the functions ...
u32 min_register_size
Minimum number of flip-flops for a register candidate to be created.
enum hal::hawkeye::DetectionConfiguration::Components components
@ 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...
std::vector< std::vector< std::string > > equivalent_types
A vector of a vector of gate types that are treated as identical types by the candidate search,...
enum hal::hawkeye::DetectionConfiguration::Control control
@ 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.
u32 timeout
Neighborhood discovery iteration timeout.