HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
verifying_candidates.cpp
Go to the documentation of this file.
7 
8 namespace hal
9 {
10  namespace module_identification
11  {
12  namespace
13  {
14  BooleanFunction create_operand(const std::vector<Net*>& op, const u32 size = 0)
15  {
16  if (op.empty())
17  {
18  log_error("module_identification", "nets are empty, cannot create bit vector");
19  return BooleanFunction();
20  }
21 
22  BooleanFunction bf;
23  const auto op_size = (size == 0) ? op.size() : size;
24  for (u32 i = 0; i < op_size; i++)
25  {
26  const auto net = op.at(i);
27 
28  BooleanFunction new_bit_bf;
29  if (net->is_gnd_net())
30  {
31  new_bit_bf = BooleanFunction::Const(BooleanFunction::Value::ZERO);
32  }
33  else if (net->is_vcc_net())
34  {
35  new_bit_bf = BooleanFunction::Const(BooleanFunction::Value::ONE);
36  }
37  else
38  {
39  new_bit_bf = BooleanFunctionNetDecorator(*net).get_boolean_variable();
40  }
41 
42  if (bf.is_empty())
43  {
44  bf = std::move(new_bit_bf);
45  }
46  else
47  {
48  auto bf_res = BooleanFunction::Concat(std::move(new_bit_bf), std::move(bf), bf.size() + 1);
49  if (bf_res.is_error())
50  {
51  log_error("module_identification", "{}", bf_res.get_error().get());
52  }
53  bf = bf_res.get();
54  }
55  }
56  return bf;
57  }
58 
59  Result<std::pair<bool, u64>> do_probe_testing(const std::vector<BooleanFunction>& actual_funcitons, const BooleanFunction& expected_function, const u32 num_tests)
60  {
61  const auto start_probe = std::chrono::steady_clock::now();
62 
63  std::srand(std::time(nullptr)); //init rand
64  for (u32 i = 0; i < num_tests; i++)
65  {
66  std::unordered_map<std::string, std::vector<BooleanFunction::Value>> test_mapping;
67  //create random inputs
68  auto variables = expected_function.get_variable_names();
69  u64 mapping = std::rand();
70  u64 current_bit = 0;
71  for (auto current_variable : variables)
72  {
73  std::vector<BooleanFunction::Value> current_input;
74  current_input.push_back(BooleanFunction::Value((mapping >> current_bit) & 1));
75  test_mapping[current_variable] = current_input;
76 
77  current_bit++;
78  }
79 
80  auto expected_result = expected_function.evaluate(test_mapping);
81  if (expected_result.is_error())
82  {
83  return ERR_APPEND(expected_result.get_error(), "failed to evalute boolean function");
84  }
85 
86  for (u32 func_idx = 0; func_idx < expected_function.size(); func_idx++)
87  {
88  const auto& actual_funciton = actual_funcitons.at(func_idx);
89  auto actual_result = actual_funciton.evaluate(test_mapping);
90  if (actual_result.is_error())
91  {
92  return ERR_APPEND(actual_result.get_error(), "failed to evalute boolean function");
93  }
94 
95  if (actual_result.get()[0] != expected_result.get()[func_idx])
96  {
97  return OK({false, std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_probe).count()});
98  }
99  }
100  }
101 
102  return OK({true, std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_probe).count()});
103  }
104 
105  Result<bool>
106  smt_check(const std::vector<BooleanFunction>& actual_funcitons, BooleanFunction&& expected_function, const u32 num_probes, std::map<std::string, std::map<std::string, u64>>& timings)
107  {
108  // const auto start_probe_timing = std::chrono::steady_clock::now();
109 
110  auto probe_res = do_probe_testing(actual_funcitons, expected_function, num_probes);
111  if (probe_res.is_error())
112  {
113  return ERR_APPEND(probe_res.get_error(), "failed selective testing on boolean function");
114  }
115  const auto [probe, probe_duration] = probe_res.get();
116 
117  timings["Probe"]["Duration"] += probe_duration;
118  if (probe)
119  {
120  timings["Probe"]["#Successful"] += 1;
121  }
122  else
123  {
124  timings["Probe"]["#Failed"] += 1;
125  return OK(false);
126  }
127 
128  const auto start_solver_timing = std::chrono::steady_clock::now();
129 
130  auto config = SMT::QueryConfig();
131  auto solver = SMT::Solver();
132 
133 #ifdef BITWUZLA_LIBRARY
134  auto s_type = SMT::SolverType::Bitwuzla;
135  auto s_call = SMT::SolverCall::Library;
136  config = config.with_solver(s_type).with_call(s_call).without_model_generation();
137 #endif
138 
139  // for (u32 idx = 0; idx < expected_function.size(); idx++)
140  // {
141  // auto bf_slice_res = BooleanFunction::Slice(expected_function.clone(), BooleanFunction::Index(idx, expected_function.size()), BooleanFunction::Index(idx, expected_function.size()), 1);
142  // if (bf_slice_res.is_error())
143  // {
144  // return ERR_APPEND(bf_slice_res.get_error(), "failed equal check: could not build single bit sliced version of expected function");
145  // }
146  // auto bf_slice = bf_slice_res.get();
147 
148  // // actual == expected
149  // auto bf_eq_res = BooleanFunction::Eq(actual_funcitons.at(idx).clone(), std::move(bf_slice), 1);
150  // if (bf_eq_res.is_error())
151  // {
152  // return ERR_APPEND(bf_eq_res.get_error(), "failed to concatenate boolean functions");
153  // }
154  // auto bf_eq = bf_eq_res.get();
155 
156  // // actual != expected
157  // auto bf_neq_res = BooleanFunction::Not(std::move(bf_eq), 1);
158  // if (bf_neq_res.is_error())
159  // {
160  // return ERR_APPEND(bf_eq_res.get_error(), "failed to concatenate boolean functions");
161  // }
162  // auto bf_neq = bf_neq_res.get();
163 
164  // auto solver_result_res = solver.with_constraint(SMT::Constraint(std::move(bf_neq))).query(config);
165  // if (solver_result_res.is_error())
166  // {
167  // return ERR_APPEND(solver_result_res.get_error(), "failed solver check for module identification utils");
168  // }
169  // auto solver_result = solver_result_res.get();
170 
171  // if (!solver_result.is_unsat())
172  // {
173  // return OK(false);
174  // }
175  // }
176  // return OK(true);
177 
178  // OLD version checking everything all at once
179 
180  // auto actual_funciton = concat_bfs(actual_funcitons);
181  auto actual_funciton = actual_funcitons.at(0).clone();
182  for (u32 i = 1; i < expected_function.size(); i++)
183  {
184  auto bf_res = BooleanFunction::Concat(actual_funcitons.at(i).clone(), std::move(actual_funciton), actual_funciton.size() + 1);
185  if (bf_res.is_error())
186  {
187  return ERR_APPEND(bf_res.get_error(), "cannot compelete equal check: failed to concatenate output functions");
188  }
189  actual_funciton = bf_res.get();
190  }
191 
192  // z == (a + b)
193  auto bf_eq_res = BooleanFunction::Eq(std::move(actual_funciton), std::move(expected_function), 1);
194  if (bf_eq_res.is_error())
195  {
196  return ERR_APPEND(bf_eq_res.get_error(), "failed to concatenate boolean functions");
197  }
198  auto bf_eq = bf_eq_res.get();
199 
200  // z != (a + b)
201  auto bf_neq_res = BooleanFunction::Not(std::move(bf_eq), 1);
202  if (bf_neq_res.is_error())
203  {
204  return ERR_APPEND(bf_eq_res.get_error(), "failed to concatenate boolean functions");
205  }
206  auto bf_neq = bf_neq_res.get();
207 
208  auto solver_result_res = solver.with_constraint(SMT::Constraint(std::move(bf_neq))).query(config);
209  if (solver_result_res.is_error())
210  {
211  return ERR_APPEND(solver_result_res.get_error(), "failed solver check for module identification utils");
212  }
213  auto solver_result = solver_result_res.get();
214 
215  const u64 solver_duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start_solver_timing).count();
216 
217  if (solver_result.is_unsat())
218  {
219  timings["Unsat_Solver_Query"]["Duration"] += solver_duration;
220  timings["Unsat_Solver_Query"]["#Amount"] += 1;
221  }
222 
223  if (solver_result.is_sat())
224  {
225  timings["Sat_Solver_Query"]["Duration"] += solver_duration;
226  timings["Sat_Solver_Query"]["#Amount"] += 1;
227  }
228 
229  if (solver_result.is_unknown())
230  {
231  timings["Unknown_Solver_Query"]["#Amount"] += 1;
232  timings["Unknown_Solver_Query"]["Duration"] += solver_duration;
233  }
234 
235  return OK({solver_result.is_unsat()});
236  }
237 
238  } // namespace
239 
240  namespace
241  {
242  Result<VerifiedCandidate> create_verified_candidate(const FunctionalCandidate& fc, const CandidateType& type, const BooleanFunction& operation)
243  {
244  return OK(VerifiedCandidate(fc.m_operands,
245  fc.m_output_nets,
246  fc.m_control_signals,
247  {fc.m_control_mapping},
248  {{fc.m_control_mapping, operation.clone()}},
249  fc.m_gates,
250  fc.m_base_gates,
251  fc.m_additional_data,
252  {type}));
253  }
254  } // namespace
255 
256  namespace
257  {
258  //counter helper
259  Result<std::pair<bool, BooleanFunction>> check_count_n(const std::vector<BooleanFunction>& output_functions,
260  BooleanFunction&& bf_i,
261  const std::vector<BooleanFunction::Value>& n_vec,
262  std::map<std::string, std::map<std::string, u64>>& timings)
263  {
264  // building constraint
265  // a + b
266  auto increment_vec = n_vec;
267 
268  while (bf_i.size() > increment_vec.size())
269  {
270  // sign extension
271  const auto msb = n_vec.back();
272  increment_vec.push_back(msb);
273  }
274 
275  auto increment = BooleanFunction::Const(increment_vec);
276 
277  auto bf_add_res = BooleanFunction::Add(std::move(bf_i), std::move(increment), bf_i.size());
278  if (bf_add_res.is_error())
279  {
280  return ERR_APPEND(bf_add_res.get_error(), "cannot check for counter: failed to build addition Boolean function");
281  }
282  auto bf_add = bf_add_res.get();
283 
284  // if the constructed sum is larger than the original sum we slice it and omit the least significant bits
285  if (bf_add.size() > output_functions.size())
286  {
287  auto bf_slice_res = BooleanFunction::Slice(std::move(bf_add),
288  BooleanFunction::Index(bf_add.size() - output_functions.size(), bf_add.size()),
289  BooleanFunction::Index(bf_add.size() - 1, bf_add.size()),
290  output_functions.size());
291 
292  if (bf_slice_res.is_error())
293  {
294  return ERR_APPEND(bf_add_res.get_error(), "cannot check for counter: failed to slice Boolean function");
295  }
296  bf_add = bf_slice_res.get();
297  }
298 
299  auto smt_check_res = smt_check(output_functions, bf_add.clone(), 8, timings);
300  if (smt_check_res.is_error())
301  {
302  return ERR_APPEND(smt_check_res.get_error(), "failed equal check for constant multiplication candidate");
303  }
304 
305  return OK({smt_check_res.get(), bf_add});
306  }
307 
308  Result<std::pair<bool, BooleanFunction>>
309  check_negation(const std::vector<BooleanFunction>& output_functions, BooleanFunction&& bf_i, std::map<std::string, std::map<std::string, u64>>& timings)
310  {
311  // building constraint
312 
313  // !a
314  auto bf_inv_res = BooleanFunction::Not(std::move(bf_i), bf_i.size());
315  if (bf_inv_res.is_error())
316  {
317  return ERR_APPEND(bf_inv_res.get_error(), "failed to concatenate boolean functions");
318  }
319  auto bf_inv = bf_inv_res.get();
320 
321  // !a + 1
322  auto bf_add_res = BooleanFunction::Add(std::move(bf_inv), BooleanFunction::Const(1, bf_inv.size()), bf_inv.size());
323  if (bf_add_res.is_error())
324  {
325  return ERR_APPEND(bf_add_res.get_error(), "failed to concatenate boolean functions");
326  }
327  auto bf_add = bf_add_res.get();
328 
329  // NOTE this is currently disabled since we are not able to reorder the input bits for the case that the output is truncated
330  // if the output is smaller than the input operands we extract the most significant bits
331  // if (bf_o.size() < bf_add.size())
332  // {
333  // const u32 offset = bf_add.size() - bf_o.size();
334  // auto bf_slice_res = BooleanFunction::Slice(std::move(bf_add), BooleanFunction::Index(offset, bf_o.size()), BooleanFunction::Index(bf_add.size() - 1, bf_o.size()), bf_o.size());
335  // if (bf_slice_res.is_error())
336  // {
337  // log_error("module_identification", "{}", bf_slice_res.get_error().get());
338  // return false;
339  // }
340  // bf_add = bf_slice_res.get();
341  // }
342 
343  if (output_functions.size() < bf_add.size())
344  {
345  return OK({false, BooleanFunction()});
346  }
347  auto smt_check_res = smt_check(output_functions, bf_add.clone(), 2, timings);
348  if (smt_check_res.is_error())
349  {
350  return ERR_APPEND(smt_check_res.get_error(), "failed equal check for constant multiplication candidate");
351  }
352 
353  return OK({smt_check_res.get(), bf_add});
354  }
355 
356  Result<VerifiedCandidate> check_sum_helper(FunctionalCandidate& fc,
357  const std::vector<BooleanFunction>& output_functions,
358  const std::vector<std::vector<Net*>>& operands,
359  const std::vector<bool>& subtract,
360  const CandidateType type,
361  std::map<std::string, std::map<std::string, u64>>& timings)
362  {
363  u32 first_op_idx = 0;
364  for (u32 op_idx = 0; op_idx < operands.size(); op_idx++)
365  {
366  if (!subtract.at(op_idx))
367  {
368  first_op_idx = op_idx;
369  break;
370  }
371  }
372 
373  auto bf_sum = create_operand(operands.at(first_op_idx));
374 
375  // SUM(operands)
376  for (u32 op_idx = 0; op_idx < operands.size(); op_idx++)
377  {
378  if (op_idx == first_op_idx)
379  {
380  continue;
381  }
382 
383  auto bf_op = create_operand(operands.at(op_idx));
384  auto bf_add_res =
385  subtract.at(op_idx) ? BooleanFunction::Sub(std::move(bf_sum), std::move(bf_op), bf_sum.size()) : BooleanFunction::Add(std::move(bf_sum), std::move(bf_op), bf_sum.size());
386  if (bf_add_res.is_error())
387  {
388  return ERR(bf_add_res.get_error().get());
389  }
390  bf_sum = bf_add_res.get();
391  }
392 
393  auto smt_check_res = smt_check(output_functions, bf_sum.clone(), 2, timings);
394  if (smt_check_res.is_error())
395  {
396  return ERR_APPEND(smt_check_res.get_error(), "failed equal check for constant multiplication candidate");
397  }
398 
399  if (smt_check_res.get())
400  {
401  const auto op_str = (subtract == std::vector<bool>{true, false}) ? "[-, +]" : (subtract == std::vector<bool>{true, false}) ? ("[+, -]") : "?";
402  fc.add_additional_data("SUM OPERATIONS", op_str);
403  return create_verified_candidate(fc, type, bf_sum);
404  }
405 
406  return OK(VerifiedCandidate());
407  }
408  } // namespace
409 
410  Result<VerifiedCandidate> check_leq(FunctionalCandidate& fc, const std::vector<BooleanFunction>& output_functions)
411  {
412  // create bit vectors
413  auto bf_a = create_operand(fc.m_operands.at(0));
414  auto bf_b = create_operand(fc.m_operands.at(1));
415 
416  // building constraint
417  // a <= b
418  if (bf_a.is_empty() || bf_b.is_empty())
419  {
420  return ERR("bit vectors of boolean function could not be generated, aborting...");
421  }
422  auto bf_leq_res = BooleanFunction::Ule(bf_a.clone(), bf_b.clone(), 1);
423  if (bf_leq_res.is_error())
424  {
425  return ERR_APPEND(bf_leq_res.get_error(), "failed to concatenate boolean functions");
426  }
427  auto bf_leq = bf_leq_res.get();
428 
429  auto leq_check_res = smt_check(output_functions, bf_leq.clone(), 2, fc.m_timings["SMT_CHECK"]["LESS_EQUAL"]);
430  if (leq_check_res.is_error())
431  {
432  return ERR_APPEND(leq_check_res.get_error(), "failed equal check for less equal candidate");
433  }
434 
435  if (leq_check_res.get())
436  {
437  return create_verified_candidate(fc, module_identification::CandidateType::less_equal, bf_leq);
438  }
439 
440  // building constraint
441  // a < b
442  auto bf_lt_res = BooleanFunction::Ult(bf_a.clone(), bf_b.clone(), 1);
443  if (bf_lt_res.is_error())
444  {
445  return ERR_APPEND(bf_lt_res.get_error(), "failed to concatenate boolean functions");
446  }
447  auto bf_lt = bf_lt_res.get();
448 
449  auto lt_check_res = smt_check(output_functions, bf_lt.clone(), 2, fc.m_timings["SMT_CHECK"]["LESS_THAN"]);
450  if (lt_check_res.is_error())
451  {
452  return ERR_APPEND(lt_check_res.get_error(), "failed equal check for less than candidate");
453  }
454 
455  if (lt_check_res.get())
456  {
457  return create_verified_candidate(fc, module_identification::CandidateType::less_than, bf_lt);
458  }
459 
460  // building constraint
461  // a <= b
462  auto bf_sleq_res = BooleanFunction::Sle(bf_a.clone(), bf_b.clone(), 1);
463  if (bf_sleq_res.is_error())
464  {
465  return ERR_APPEND(bf_sleq_res.get_error(), "failed to concatenate boolean functions");
466  }
467  auto bf_sleq = bf_sleq_res.get();
468 
469  auto sleq_check_res = smt_check(output_functions, bf_sleq.clone(), 2, fc.m_timings["SMT_CHECK"]["SIGNED_LESS_EQUAL"]);
470  if (sleq_check_res.is_error())
471  {
472  return ERR_APPEND(sleq_check_res.get_error(), "failed equal check for signed less equal candidate");
473  }
474 
475  if (sleq_check_res.get())
476  {
477  return create_verified_candidate(fc, module_identification::CandidateType::signed_less_equal, bf_sleq);
478  }
479 
480  // building constraint
481  // a < b
482  auto bf_slt_res = BooleanFunction::Slt(bf_a.clone(), bf_b.clone(), 1);
483  if (bf_slt_res.is_error())
484  {
485  return ERR_APPEND(bf_slt_res.get_error(), "failed to concatenate boolean functions");
486  }
487  auto bf_slt = bf_slt_res.get();
488 
489  auto slt_check_res = smt_check(output_functions, bf_slt.clone(), 2, fc.m_timings["SMT_CHECK"]["SIGNED_LESS_THAN"]);
490  if (slt_check_res.is_error())
491  {
492  return ERR_APPEND(slt_check_res.get_error(), "failed equal check for signed less than candidate");
493  }
494 
495  if (slt_check_res.get())
496  {
497  return create_verified_candidate(fc, module_identification::CandidateType::signed_less_than, bf_slt);
498  }
499 
500  return OK(VerifiedCandidate());
501  }
502 
503  Result<VerifiedCandidate> check_addition(FunctionalCandidate& fc, const std::vector<BooleanFunction>& output_functions)
504  {
505  auto bf_sum = create_operand(fc.m_operands.at(0));
506 
507  // SUM(operands)
508  for (u32 op_idx = 1; op_idx < fc.m_operands.size(); op_idx++)
509  {
510  auto bf_op = create_operand(fc.m_operands.at(op_idx));
511  auto bf_add_res = BooleanFunction::Add(std::move(bf_sum), std::move(bf_op), bf_sum.size());
512  if (bf_add_res.is_error())
513  {
514  return ERR_APPEND(bf_add_res.get_error(), "failed to concatenate boolean functions");
515  }
516  bf_sum = bf_add_res.get();
517  }
518 
519  auto smt_check_res = smt_check(output_functions, bf_sum.clone(), 8, fc.m_timings["SMT_CHECK"]["ADD"]);
520  if (smt_check_res.is_error())
521  {
522  return ERR_APPEND(smt_check_res.get_error(), "failed equal check for constant multiplication candidate");
523  }
524 
525  if (smt_check_res.get())
526  {
527  return create_verified_candidate(fc, CandidateType::addition, bf_sum);
528  }
529 
530  return OK(VerifiedCandidate());
531  }
532 
533  Result<VerifiedCandidate> check_addition_offset(FunctionalCandidate& fc, const std::vector<BooleanFunction>& output_functions)
534  {
535  auto bf_sum = create_operand(fc.m_operands.at(0));
536 
537  // SUM(operands)
538  for (u32 op_idx = 1; op_idx < fc.m_operands.size(); op_idx++)
539  {
540  auto bf_op = create_operand(fc.m_operands.at(op_idx));
541  auto bf_add_res = BooleanFunction::Add(std::move(bf_sum), std::move(bf_op), bf_sum.size());
542  if (bf_add_res.is_error())
543  {
544  return ERR_APPEND(bf_add_res.get_error(), "failed to concatenate boolean functions");
545  }
546  bf_sum = bf_add_res.get();
547  }
548 
549  // check for a constant offset
550  auto bf_o = output_functions.at(0);
551  for (u32 i = 1; i < output_functions.size(); i++)
552  {
553  auto bf_res = BooleanFunction::Concat(output_functions.at(i).clone(), std::move(bf_o), bf_o.size() + 1);
554  if (bf_res.is_error())
555  {
556  return ERR_APPEND(bf_res.get_error(), "cannot check for counter: failed to build conactenated output function");
557  }
558  bf_o = bf_res.get();
559  }
560 
561  std::map<std::string, BooleanFunction> eval_mapping;
562  for (const auto& var : bf_o.get_variable_names())
563  {
564  eval_mapping.insert({var, BooleanFunction::Const(0, 1)});
565  }
566 
567  const auto substitution_res = bf_o.substitute(eval_mapping);
568  if (substitution_res.is_error())
569  {
570  return ERR_APPEND(substitution_res.get_error(), "cannot check for constant offset: failed to evaluate output functions for zero input");
571  }
572  const auto eval = substitution_res.get().simplify_local();
573 
574  const auto increment_res = eval.get_constant_value();
575  if (increment_res.is_error())
576  {
577  return ERR_APPEND(increment_res.get_error(), "cannot check for constant offset: failed to get constant value of substituted boolean function");
578  }
579  const auto increment_vec = increment_res.get();
580  const auto increment = BooleanFunction::Const(increment_vec);
581 
582  if (!increment.has_constant_value(0))
583  {
584  auto bf_sum_plus_offset = BooleanFunction::Add(bf_sum.clone(), increment.clone(), bf_sum.size());
585  if (bf_sum_plus_offset.is_error())
586  {
587  return ERR_APPEND(bf_sum_plus_offset.get_error(), "failed to build sum boolean functions");
588  }
589  bf_sum = bf_sum_plus_offset.get();
590  }
591  else
592  {
593  // Do not check a candidate with a zero offset
594  return OK(VerifiedCandidate());
595  }
596 
597  auto smt_check_res = smt_check(output_functions, bf_sum.clone(), 8, fc.m_timings["SMT_CHECK"]["ADD"]);
598  if (smt_check_res.is_error())
599  {
600  return ERR_APPEND(smt_check_res.get_error(), "failed equal check for constant multiplication candidate");
601  }
602 
603  if (smt_check_res.get())
604  {
605  return create_verified_candidate(fc, CandidateType::addition_offset, bf_sum);
606  }
607 
608  return OK(VerifiedCandidate());
609  }
610 
611  Result<VerifiedCandidate> check_sub(FunctionalCandidate& fc, const std::vector<BooleanFunction>& output_functions, const std::vector<std::vector<Gate*>>& registers)
612  {
613  if (fc.m_operands.size() != 2)
614  {
615  return OK(VerifiedCandidate());
616  }
617 
618  std::vector<VerifiedCandidate> possible_results;
619 
620  for (u32 pos = 1; pos < output_functions.size(); pos++)
621  {
622  // auto bf_o = create_operand(output_functions, pos + 1);
623  auto bf_a = create_operand(fc.m_operands.at(0), pos + 1);
624  auto bf_b = create_operand(fc.m_operands.at(1), pos + 1);
625 
626  // building constraint
627  // a - b
628  auto bf_sum_res = BooleanFunction::Sub(std::move(bf_a), std::move(bf_b), pos + 1);
629  if (bf_sum_res.is_error())
630  {
631  return ERR_APPEND(bf_sum_res.get_error(), "failed to concatenate boolean functions");
632  }
633  auto bf_sum = bf_sum_res.get();
634 
635  auto smt_check_res = smt_check(output_functions, bf_sum.clone(), 8, fc.m_timings["SMT_CHECK"]["SUB"]);
636  if (smt_check_res.is_error())
637  {
638  return ERR_APPEND(smt_check_res.get_error(), "failed equal check for constant multiplication candidate");
639  }
640 
641  if (smt_check_res.get())
642  {
643  if (pos == (output_functions.size() - 1))
644  {
645  possible_results.push_back(create_verified_candidate(fc, CandidateType::subtraction, bf_sum).get());
646  }
647  else
648  {
649  continue;
650  }
651  }
652 
653  // first check failed swap -> last input bits
654  auto tmp = std::move(fc.m_operands.at(0).at(pos - 1));
655  fc.m_operands.at(0).at(pos - 1) = std::move(fc.m_operands.at(1).at(pos - 1));
656  fc.m_operands.at(1).at(pos - 1) = tmp;
657 
658  // bf_o = create_operand(output_functions, pos + 1);
659  bf_a = create_operand(fc.m_operands.at(0), pos + 1);
660  bf_b = create_operand(fc.m_operands.at(1), pos + 1);
661 
662  // a - b
663  auto bf_swapped_sum_res = BooleanFunction::Sub(std::move(bf_a), std::move(bf_b), pos + 1);
664  if (bf_swapped_sum_res.is_error())
665  {
666  return ERR_APPEND(bf_swapped_sum_res.get_error(), "failed to concatenate boolean functions");
667  }
668  auto bf_swapped_sum = bf_swapped_sum_res.get();
669 
670  auto smt_check_res_2 = smt_check(output_functions, bf_swapped_sum.clone(), 8, fc.m_timings["SMT_CHECK"]["SUB"]);
671  if (smt_check_res_2.is_error())
672  {
673  return ERR_APPEND(smt_check_res_2.get_error(), "failed equal check for constant multiplication candidate");
674  }
675 
676  if (smt_check_res_2.get())
677  {
678  if (pos == (output_functions.size() - 1))
679  {
680  possible_results.push_back(create_verified_candidate(fc, CandidateType::subtraction, bf_swapped_sum).get());
681  }
682  else
683  {
684  continue;
685  }
686  }
687 
688  if (!possible_results.empty())
689  {
690  break;
691  }
692 
693  // second check failed -> no valid sub
694  return OK(VerifiedCandidate());
695  }
696 
697  // compare possible results against each other based on the amount of source registers for each operand
698  std::sort(possible_results.begin(), possible_results.end(), [&registers](const auto& vc1, const auto& vc2) {
699  u32 op_reg_score_1 = 0;
700  u32 op_reg_score_2 = 0;
701 
702  for (const auto& op : vc1.m_operands)
703  {
704  op_reg_score_1 += find_neighboring_registers(op, registers).size();
705  }
706 
707  for (const auto& op : vc2.m_operands)
708  {
709  op_reg_score_2 += find_neighboring_registers(op, registers).size();
710  }
711 
712  return op_reg_score_2 < op_reg_score_1;
713  });
714 
715  return OK(possible_results.front());
716  }
717 
718  Result<VerifiedCandidate> check_sliced_add(FunctionalCandidate& fc, const std::vector<BooleanFunction>& output_functions)
719  {
720  // check whether the outputs require reordering
721  // count the input variables to each output function
722  std::map<u32, u32> input_var_count;
723  for (u32 idx = 0; idx < output_functions.size(); idx++)
724  {
725  const auto& func = output_functions.at(idx);
726  input_var_count.insert({idx, func.get_variable_names().size()});
727  }
728 
729  std::map<u32, std::vector<u32>> count_to_indices;
730  for (const auto& [idx, c] : input_var_count)
731  {
732  count_to_indices[c].push_back(idx);
733  }
734 
735  u32 overfull_bins = 0;
736  for (const auto& [c, indices] : count_to_indices)
737  {
738  if (indices.size() > 1)
739  {
740  overfull_bins++;
741  }
742  }
743 
744  // we can only handle one overfull bin, if there are no overfull bins reordering is not required
745  if (overfull_bins != 1)
746  {
747  return OK(VerifiedCandidate());
748  }
749 
750  // we can only handle cases with the "last" bin being the overfull bin
751  if (count_to_indices.rbegin()->second.size() == 1)
752  {
753  return OK(VerifiedCandidate());
754  }
755  if (count_to_indices.size() < 2)
756  {
757  return OK(VerifiedCandidate());
758  }
759 
760  std::vector<u32> next_bit_candidates = count_to_indices.rbegin()->second;
761 
762  std::vector<BooleanFunction> ordered_output_functions;
763  std::vector<Net*> ordered_output_nets;
764  for (const auto& [_c, indices] : count_to_indices)
765  {
766  if (indices.size() != 1)
767  {
768  continue;
769  }
770 
771  ordered_output_functions.push_back(output_functions.at(indices.front()).clone());
772  ordered_output_nets.push_back(fc.m_output_nets.at(indices.front()));
773  }
774 
775  // SUM(operands)
776  auto bf_sum = create_operand(fc.m_operands.at(0));
777  for (u32 op_idx = 1; op_idx < fc.m_operands.size(); op_idx++)
778  {
779  auto bf_op = create_operand(fc.m_operands.at(op_idx));
780  auto bf_add_res = BooleanFunction::Add(std::move(bf_sum), std::move(bf_op), bf_sum.size());
781  if (bf_add_res.is_error())
782  {
783  return ERR_APPEND(bf_add_res.get_error(), "failed to concatenate boolean functions");
784  }
785  bf_sum = bf_add_res.get();
786  }
787 
788  const auto initial_size = bf_sum.size();
789  const auto initial_end_index = ordered_output_functions.size();
790  auto initial_i0 = BooleanFunction::Index(0, initial_size);
791  auto initial_i1 = BooleanFunction::Index(initial_end_index - 1, initial_size);
792  auto initial_bf_slice_res = BooleanFunction::Slice(bf_sum.clone(), std::move(initial_i0), std::move(initial_i1), initial_end_index);
793  if (initial_bf_slice_res.is_error())
794  {
795  return ERR_APPEND(initial_bf_slice_res.get_error(), "cannot check addition slice: failed to build sliced boolean function");
796  }
797  auto initial_bf_slice = initial_bf_slice_res.get();
798 
799  auto initial_smt_check_res = smt_check(output_functions, std::move(initial_bf_slice), 2, fc.m_timings["SMT_CHECK"]["ADD_SLICED"]);
800  if (initial_smt_check_res.is_error())
801  {
802  return ERR_APPEND(initial_smt_check_res.get_error(), "failed equal check for sliced add candidate");
803  }
804 
805  if (!initial_smt_check_res.get())
806  {
807  return OK(VerifiedCandidate());
808  }
809 
810  while (!next_bit_candidates.empty())
811  {
812  bool found_valid_idx = false;
813  u32 valid_idx;
814  for (const auto& idx : next_bit_candidates)
815  {
816  auto tmp = ordered_output_functions;
817  tmp.push_back(output_functions.at(idx).clone());
818 
819  const auto size = bf_sum.size();
820  const auto end_index = tmp.size();
821  auto i0 = BooleanFunction::Index(0, size);
822  auto i1 = BooleanFunction::Index(end_index - 1, size);
823  auto bf_slice_res = BooleanFunction::Slice(bf_sum.clone(), std::move(i0), std::move(i1), end_index);
824  if (bf_slice_res.is_error())
825  {
826  return ERR_APPEND(bf_slice_res.get_error(), "cannot check addition slice: failed to build sliced boolean function");
827  }
828  auto bf_slice = bf_slice_res.get();
829 
830  auto smt_check_res = smt_check(output_functions, bf_slice.clone(), 2, fc.m_timings["SMT_CHECK"]["ADD_SLICED"]);
831  if (smt_check_res.is_error())
832  {
833  return ERR_APPEND(smt_check_res.get_error(), "failed equal check for constant multiplication candidate");
834  }
835 
836  if (smt_check_res.get())
837  {
838  found_valid_idx = true;
839  valid_idx = idx;
840 
841  if (next_bit_candidates.size() == 1)
842  {
843  return create_verified_candidate(fc, CandidateType::addition, bf_slice);
844  }
845 
846  // TODO check whether we can insert this break
847  break;
848  }
849  }
850 
851  if (!found_valid_idx)
852  {
853  return OK(VerifiedCandidate());
854  }
855 
856  next_bit_candidates.erase(std::remove(next_bit_candidates.begin(), next_bit_candidates.end(), valid_idx), next_bit_candidates.end());
857 
858  ordered_output_functions.push_back(output_functions.at(valid_idx).clone());
859  ordered_output_nets.push_back(fc.m_output_nets.at(valid_idx));
860  }
861 
862  return OK(VerifiedCandidate());
863  }
864 
865  Result<VerifiedCandidate> check_add_sub(FunctionalCandidate& fc, const std::vector<BooleanFunction>& output_functions, const std::vector<std::vector<Gate*>>& registers)
866  {
867  if (fc.m_operands.size() < 2)
868  {
869  return OK(VerifiedCandidate());
870  }
871 
872  auto check_add_res = check_addition(fc, output_functions);
873  if (check_add_res.is_error())
874  {
875  return check_add_res;
876  }
877  if (check_add_res.get().is_verified())
878  {
879  return check_add_res;
880  }
881 
882  auto check_sub_res = check_sub(fc, output_functions, registers);
883  if (check_sub_res.is_error())
884  {
885  return check_sub_res;
886  }
887  if (check_sub_res.get().is_verified())
888  {
889  return check_sub_res;
890  }
891 
892  // TODO check whether we need this
893  // auto check_sliced_add_res = check_sliced_add(fc, output_functions);
894  // if (check_sliced_add_res.is_error())
895  // {
896  // return check_sliced_add_res;
897  // }
898  // if (check_sliced_add_res.get().is_verified())
899  // {
900  // return check_sliced_add_res;
901  // }
902 
903  return OK(VerifiedCandidate());
904  }
905 
906  Result<VerifiedCandidate> check_add_sub_offset(FunctionalCandidate& fc, const std::vector<BooleanFunction>& output_functions, const std::vector<std::vector<Gate*>>& registers)
907  {
908  if (fc.m_operands.size() < 2)
909  {
910  return OK(VerifiedCandidate());
911  }
912 
913  auto check_add_res = check_addition_offset(fc, output_functions);
914  if (check_add_res.is_error())
915  {
916  return check_add_res;
917  }
918  if (check_add_res.get().is_verified())
919  {
920  return check_add_res;
921  }
922 
923  return OK(VerifiedCandidate());
924  }
925 
926  Result<VerifiedCandidate> check_value_check(FunctionalCandidate& fc, const std::vector<BooleanFunction>& output_functions)
927  {
928  auto bf_i = create_operand(fc.m_operands.at(0));
929 
930  // create the solver
931  auto s = SMT::Solver();
932  auto config = SMT::QueryConfig();
933  config.with_model_generation();
934 
935 #ifdef BITWUZLA_LIBRARY
936  auto s_type = SMT::SolverType::Bitwuzla;
937  auto s_call = SMT::SolverCall::Library;
938  config.with_solver(s_type).with_call(s_call);
939 #endif
940 
941  s = s.with_constraint(SMT::Constraint(output_functions.front().clone()));
942 
943  auto first_result_res = s.query(config);
944  if (first_result_res.is_error())
945  {
946  return ERR_APPEND(first_result_res.get_error(), "failed smt run on boolean function");
947  }
948  auto first_result = first_result_res.get();
949 
950  if (!first_result.is_sat())
951  {
952  return OK(VerifiedCandidate());
953  }
954 
955  const auto eval_res = first_result.model.value().evaluate(bf_i);
956  if (eval_res.is_error())
957  {
958  return ERR_APPEND(eval_res.get_error(), "failed to evaluate boolean functions");
959  }
960  auto bf_m = eval_res.get();
961 
962  // bf_i == bf_m
963  auto bf_eq_res = BooleanFunction::Eq(std::move(bf_i), std::move(bf_m), 1);
964  if (bf_eq_res.is_error())
965  {
966  return ERR_APPEND(bf_eq_res.get_error(), "failed to concatenate boolean functions");
967  }
968  auto bf_eq = bf_eq_res.get();
969 
970  // bf_i != bf_m
971  auto bf_neq_res = BooleanFunction::Not(std::move(bf_eq), 1);
972  if (bf_neq_res.is_error())
973  {
974  return ERR_APPEND(bf_neq_res.get_error(), "failed to concatenate boolean functions");
975  }
976  auto bf_neq = bf_neq_res.get();
977 
978  s = s.with_constraint(SMT::Constraint(bf_neq.clone()));
979 
980  auto second_result_res = s.query(config);
981  if (second_result_res.is_error())
982  {
983  return ERR_APPEND(second_result_res.get_error(), "failed smt run on boolean function");
984  }
985  auto second_result = second_result_res.get();
986 
987  if (!second_result.is_unsat())
988  {
989  return OK(VerifiedCandidate());
990  }
991 
992  // TODO this should probably go somewhere else
993  // std::map<std::string, std::vector<Net*>> inputs;
994  // for (const auto& net : fc.m_operands.at(0))
995  // {
996  // auto bf_val_res = first_result.model.value().evaluate(BooleanFunctionNetDecorator(*net).get_boolean_variable());
997  // if (bf_val_res.is_error())
998  // {
999  // return ERR_APPEND(bf_val_res.get_error(), "failed to evaluate boolean function");
1000  // }
1001  // auto bf_val = bf_val_res.get();
1002 
1003  // if (bf_val.has_constant_value(0))
1004  // {
1005  // inputs["ZERO"].push_back(net);
1006  // }
1007  // else if (bf_val.has_constant_value(1))
1008  // {
1009  // inputs["ONE"].push_back(net);
1010  // }
1011  // }
1012 
1013  return create_verified_candidate(fc, CandidateType::value_check, BooleanFunction());
1014  }
1015 
1016  Result<VerifiedCandidate> check_constant_multiplication(FunctionalCandidate& fc, const std::vector<BooleanFunction>& output_functions)
1017  {
1018  if (fc.m_operands.size() < 2)
1019  {
1020  return OK(VerifiedCandidate());
1021  }
1022 
1023  auto bf_sum = create_operand(fc.m_operands.at(0));
1024 
1025  // building constraint
1026  // SUM(operands)
1027  for (u32 op_idx = 1; op_idx < fc.m_operands.size(); op_idx++)
1028  {
1029  auto bf_op = create_operand(fc.m_operands.at(op_idx));
1030  auto bf_add_res = BooleanFunction::Add(std::move(bf_sum), std::move(bf_op), bf_sum.size());
1031  if (bf_add_res.is_error())
1032  {
1033  return ERR_APPEND(bf_add_res.get_error(), "failed to add boolean functions");
1034  }
1035  bf_sum = bf_add_res.get();
1036  }
1037 
1038  auto smt_check_res = smt_check(output_functions, bf_sum.clone(), 2, fc.m_timings["SMT_CHECK"]["CONST_MULT"]);
1039  if (smt_check_res.is_error())
1040  {
1041  return ERR_APPEND(smt_check_res.get_error(), "failed equal check for constant multiplication candidate");
1042  }
1043 
1044  if (smt_check_res.get())
1045  {
1046  return create_verified_candidate(fc, CandidateType::constant_multiplication, bf_sum);
1047  }
1048 
1049  // for candidates with only two oeprands we check for a subtraction larger_operand - smaller_operand
1050  if (fc.m_operands.size() == 2)
1051  {
1052  // a single shift to the right with a subtraction is equivalent to a counter with the lowest bit omitted, therefore we dont check for constant multiplication in that case
1053  // if (auto it = fc.m_additional_data.find("OPERAND_SHIFTS"); it != fc.m_additional_data.end())
1054  // {
1055  // if (it->second == "-1")
1056  // {
1057  // return OK(VerifiedCandidate());
1058  // }
1059  // }
1060 
1061  auto sum_check_res_1 = check_sum_helper(fc, output_functions, fc.m_operands, {false, true}, CandidateType::constant_multiplication, fc.m_timings["SMT_CHECK"]["CONST_MULT"]);
1062  if (sum_check_res_1.is_error())
1063  {
1064  return ERR_APPEND(sum_check_res_1.get_error(), "failed to execute sum_check_helper in first variant");
1065  }
1066  if (const auto c = sum_check_res_1.get(); c.is_verified())
1067  {
1068  return OK(c);
1069  }
1070 
1071  auto sum_check_res_2 = check_sum_helper(fc, output_functions, fc.m_operands, {true, false}, CandidateType::constant_multiplication, fc.m_timings["SMT_CHECK"]["CONST_MULT"]);
1072  if (sum_check_res_2.is_error())
1073  {
1074  return ERR_APPEND(sum_check_res_2.get_error(), "failed to execute sum_check_helper in first variant");
1075  }
1076  if (const auto c = sum_check_res_2.get(); c.is_verified())
1077  {
1078  return OK(c);
1079  }
1080  }
1081 
1082  return OK(VerifiedCandidate());
1083  }
1084 
1085  Result<VerifiedCandidate> check_constant_multiplication_offset(FunctionalCandidate& fc, const std::vector<BooleanFunction>& output_functions)
1086  {
1087  if (fc.m_operands.size() < 2)
1088  {
1089  return OK(VerifiedCandidate());
1090  }
1091 
1092  auto bf_sum = create_operand(fc.m_operands.at(0));
1093 
1094  // building constraint
1095  // SUM(operands)
1096  for (u32 op_idx = 1; op_idx < fc.m_operands.size(); op_idx++)
1097  {
1098  auto bf_op = create_operand(fc.m_operands.at(op_idx));
1099  auto bf_add_res = BooleanFunction::Add(std::move(bf_sum), std::move(bf_op), bf_sum.size());
1100  if (bf_add_res.is_error())
1101  {
1102  return ERR_APPEND(bf_add_res.get_error(), "failed to add boolean functions");
1103  }
1104  bf_sum = bf_add_res.get();
1105  }
1106 
1107  auto bf_o = output_functions.at(0);
1108  for (u32 i = 1; i < output_functions.size(); i++)
1109  {
1110  auto bf_res = BooleanFunction::Concat(output_functions.at(i).clone(), std::move(bf_o), bf_o.size() + 1);
1111  if (bf_res.is_error())
1112  {
1113  return ERR_APPEND(bf_res.get_error(), "cannot check for counter: failed to build conactenated output function");
1114  }
1115  bf_o = bf_res.get();
1116  }
1117 
1118  // check for a constant offset
1119  std::set<std::string> input_operands = bf_o.get_variable_names();
1120  std::map<std::string, BooleanFunction> eval_mapping;
1121  for (const auto& operand : input_operands)
1122  {
1123  eval_mapping.insert({operand, BooleanFunction::Const(0, 1)});
1124  }
1125 
1126  const auto substitution_res = bf_o.substitute(eval_mapping);
1127  if (substitution_res.is_error())
1128  {
1129  return ERR_APPEND(substitution_res.get_error(), "cannot check for constant offset: failed to evaluate output functions for zero input");
1130  }
1131  const auto eval = substitution_res.get().simplify_local();
1132 
1133  const auto increment_res = eval.get_constant_value();
1134  if (increment_res.is_error())
1135  {
1136  return ERR_APPEND(increment_res.get_error(), "cannot check for constant offset: failed to get constant value of substituted boolean function");
1137  }
1138  const auto increment_vec = increment_res.get();
1139  const auto increment = BooleanFunction::Const(increment_vec);
1140 
1141  if (!increment.has_constant_value(0))
1142  {
1143  auto bf_inc_res = BooleanFunction::Add(std::move(bf_sum), increment.clone(), bf_sum.size());
1144 
1145  if (bf_inc_res.is_error())
1146  {
1147  return ERR_APPEND(bf_inc_res.get_error(), "failed to add increment to boolean function");
1148  }
1149  bf_sum = bf_inc_res.get();
1150  }
1151  else
1152  {
1153  // Do not check for an offest candidate with a 0 offset
1154  return OK(VerifiedCandidate());
1155  }
1156 
1157  auto smt_check_res = smt_check(output_functions, bf_sum.clone(), 2, fc.m_timings["SMT_CHECK"]["CONST_MULT"]);
1158  if (smt_check_res.is_error())
1159  {
1160  return ERR_APPEND(smt_check_res.get_error(), "failed equal check for constant multiplication candidate");
1161  }
1162 
1163  if (smt_check_res.get())
1164  {
1165  return create_verified_candidate(fc, CandidateType::constant_multiplication_offset, bf_sum);
1166  }
1167 
1168  // sum with subtractions not implemented
1169 
1170  return OK(VerifiedCandidate());
1171  }
1172 
1173  Result<VerifiedCandidate> check_counter(FunctionalCandidate& fc, const std::vector<BooleanFunction>& output_functions)
1174  {
1175  auto bf_i = create_operand(fc.m_operands.at(0));
1176  auto bf_o = output_functions.at(0);
1177  for (u32 i = 1; i < output_functions.size(); i++)
1178  {
1179  auto bf_res = BooleanFunction::Concat(output_functions.at(i).clone(), std::move(bf_o), bf_o.size() + 1);
1180  if (bf_res.is_error())
1181  {
1182  return ERR_APPEND(bf_res.get_error(), "cannot check for counter: failed to build conactenated output function");
1183  }
1184  bf_o = bf_res.get();
1185  }
1186 
1187  // figure out operand
1188  std::set<std::string> input_operands = bf_i.get_variable_names();
1189  std::map<std::string, BooleanFunction> eval_mapping;
1190  for (const auto& operand : input_operands)
1191  {
1192  eval_mapping.insert({operand, BooleanFunction::Const(0, 1)});
1193  }
1194 
1195  const auto substitution_res = bf_o.substitute(eval_mapping);
1196  if (substitution_res.is_error())
1197  {
1198  return ERR_APPEND(substitution_res.get_error(), "cannot check for counter: failed to evaluate output functions for zero input");
1199  }
1200  const auto eval = substitution_res.get().simplify_local();
1201 
1202  const auto increment_res = eval.get_constant_value();
1203  if (increment_res.is_error())
1204  {
1205  return ERR_APPEND(increment_res.get_error(), "cannot check for counter: failed to get constant value of substituted boolean function");
1206  }
1207  const auto increment_vec = increment_res.get();
1208  const auto increment = BooleanFunction::Const(increment_vec);
1209 
1210  auto counter_check_res = check_count_n(output_functions, bf_i.clone(), increment_vec, fc.m_timings["SMT_CHECK"]["COUNTER"]);
1211  if (counter_check_res.is_error())
1212  {
1213  return ERR_APPEND(counter_check_res.get_error(), "failed to run counter check for value: " + increment.to_string());
1214  }
1215  auto [is_counter, bf_count] = counter_check_res.get();
1216  if (is_counter)
1217  {
1218  fc.add_additional_data("COUNTER_INCREMENT", increment.to_string());
1219  return create_verified_candidate(fc, CandidateType::counter, bf_count);
1220  }
1221 
1222  auto check_negation_res = check_negation(output_functions, bf_i.clone(), fc.m_timings["SMT_CHECK"]["NEGATION"]);
1223  if (check_negation_res.is_error())
1224  {
1225  return ERR_APPEND(check_negation_res.get_error(), "failed checknegation during check_counter");
1226  }
1227  auto [is_negation, bf_neg] = check_negation_res.get();
1228  if (is_negation)
1229  {
1230  return create_verified_candidate(fc, CandidateType::negation, bf_neg);
1231  }
1232 
1233  return OK(VerifiedCandidate());
1234  }
1235 
1236  Result<VerifiedCandidate> check_absolute(FunctionalCandidate& fc, const std::vector<BooleanFunction>& output_functions)
1237  {
1238  auto bf_i = create_operand(fc.m_operands.at(0));
1239 
1240  // building constraint
1241  // !a
1242  auto bf_inv_res = BooleanFunction::Not(std::move(bf_i), bf_i.size());
1243  if (bf_inv_res.is_error())
1244  {
1245  return ERR_APPEND(bf_inv_res.get_error(), "failed to concatenate boolean functions");
1246  }
1247  auto bf_inv = bf_inv_res.get();
1248 
1249  // !a + 1
1250  auto bf_neg_res = BooleanFunction::Add(std::move(bf_inv), BooleanFunction::Const(1, bf_inv.size()), bf_inv.size());
1251  if (bf_neg_res.is_error())
1252  {
1253  return ERR_APPEND(bf_neg_res.get_error(), "failed to concatenate boolean functions");
1254  }
1255  auto bf_neg = bf_neg_res.get();
1256 
1257  // a[MSB : MSB]
1258  auto bf_a_msb_res = BooleanFunction::Slice(bf_i.clone(), BooleanFunction::Index(bf_i.size() - 1, bf_i.size()), BooleanFunction::Index(bf_i.size() - 1, bf_i.size()), 1);
1259  if (bf_a_msb_res.is_error())
1260  {
1261  return ERR_APPEND(bf_a_msb_res.get_error(), "failed to concatenate boolean functions");
1262  }
1263  auto bf_a_msb = bf_a_msb_res.get();
1264 
1265  // if a[MSB:MSB] == 1 ? (!a + 1) : a
1266  auto bf_a_abs_res = BooleanFunction::Ite(bf_a_msb.clone(), bf_neg.clone(), bf_i.clone(), bf_i.size());
1267  if (bf_a_abs_res.is_error())
1268  {
1269  return ERR_APPEND(bf_a_abs_res.get_error(), "failed to concatenate boolean functions");
1270  }
1271  auto bf_a_abs = bf_a_abs_res.get();
1272 
1273  auto smt_check_res = smt_check(output_functions, bf_a_abs.clone(), 2, fc.m_timings["SMT_CHECK"]["ABSOLUTE"]);
1274  if (smt_check_res.is_error())
1275  {
1276  return ERR_APPEND(smt_check_res.get_error(), "failed equal check for constant multiplication candidate");
1277  }
1278 
1279  if (smt_check_res.get())
1280  {
1281  return create_verified_candidate(fc, CandidateType::absolute, bf_a_abs);
1282  }
1283 
1284  return OK(VerifiedCandidate());
1285  }
1286 
1287  Result<VerifiedCandidate> check_equal(FunctionalCandidate& fc, const std::vector<BooleanFunction>& output_functions)
1288  {
1289  // try and find the correct order for input
1290  std::unordered_map<std::string, BooleanFunction::Value> input_mapping;
1291  std::set<std::string> vars = output_functions[0].get_variable_names();
1292  // create mapping from name to Net*
1293  Netlist* nl = fc.m_input_nets.front()->get_netlist();
1294  std::unordered_map<Net*, std::string> net_mapping;
1295  std::vector<Net*> input_nets;
1296  for (std::string cur_name : vars)
1297  {
1298  Net* net = BooleanFunctionNetDecorator::get_net_from(nl, cur_name).get();
1299  input_nets.push_back(net);
1300  net_mapping.insert(std::make_pair<Net*, std::string>(std::move(net), std::move(cur_name)));
1301  }
1302 
1303  // set all inputs to zero
1304  for (std::string cur_var_name : vars)
1305  {
1306  input_mapping.insert(std::make_pair<std::string, BooleanFunction::Value>(std::move(cur_var_name), BooleanFunction::Value::ZERO));
1307  }
1308  std::vector<std::vector<Net*>> operands;
1309  operands.push_back(std::vector<Net*>());
1310  operands.push_back(std::vector<Net*>());
1311 
1312  std::vector<Net*> unused_inputs;
1313  unused_inputs.insert(unused_inputs.end(), input_nets.begin(), input_nets.end());
1314  for (Net* cur_input : input_nets)
1315  {
1316  if (std::find(unused_inputs.begin(), unused_inputs.end(), cur_input) == unused_inputs.end())
1317  {
1318  // element was already used
1319  continue;
1320  }
1321  auto firstit = std::find(unused_inputs.begin(), unused_inputs.end(), cur_input);
1322  unused_inputs.erase(firstit);
1323 
1324  operands.at(0).push_back(cur_input);
1325  // set input mapping of Net to true to find partner;
1326  input_mapping[net_mapping[cur_input]] = BooleanFunction::Value::ONE;
1327  bool found_b = false;
1328  for (Net* cur_b_candidate : unused_inputs)
1329  {
1330  input_mapping[net_mapping[cur_b_candidate]] = BooleanFunction::Value::ONE;
1331  Result<BooleanFunction::Value> res = output_functions[0].evaluate(input_mapping);
1332  if (res.is_error())
1333  {
1334  return ERR_APPEND(res.get_error(), "failed to evaluate boolean function");
1335  }
1336 
1337  if (res.get() == BooleanFunction::Value::ONE)
1338  {
1339  found_b = true;
1340  // operand_b.push_back(cur_b_candidate);
1341 
1342  operands.at(1).push_back(cur_b_candidate);
1343  auto it = std::find(unused_inputs.begin(), unused_inputs.end(), cur_b_candidate);
1344  unused_inputs.erase(it);
1345  break;
1346  }
1347  else
1348  {
1349  input_mapping[net_mapping[cur_b_candidate]] = BooleanFunction::Value::ZERO;
1350  }
1351  }
1352  if (found_b == false)
1353  {
1354  return OK(VerifiedCandidate());
1355  }
1356  }
1357 
1358  // now we found an input order for a and b
1359  // time to evaluate
1360 
1361  auto bf_a = create_operand(operands.at(0));
1362  auto bf_b = create_operand(operands.at(1));
1363 
1364  if (bf_a.is_empty() || bf_b.is_empty())
1365  {
1366  return ERR("bit vectors of boolean function could not be generated, aborting...");
1367  }
1368 
1369  // building constraint
1370  // a == b
1371  auto bf_eq_res = BooleanFunction::Eq(std::move(bf_a), std::move(bf_b), 1);
1372  if (bf_eq_res.is_error())
1373  {
1374  return ERR_APPEND(bf_eq_res.get_error(), "failed to concatenate boolean functions");
1375  }
1376  auto bf_eq = bf_eq_res.get();
1377 
1378  auto smt_check_res = smt_check(output_functions, bf_eq.clone(), 2, fc.m_timings["SMT_CHECK"]["EQUAL"]);
1379  if (smt_check_res.is_error())
1380  {
1381  return ERR_APPEND(smt_check_res.get_error(), "failed equal check for constant multiplication candidate");
1382  }
1383 
1384  if (smt_check_res.get())
1385  {
1386  return create_verified_candidate(fc, CandidateType::equal, bf_eq);
1387  }
1388 
1389  return OK(VerifiedCandidate());
1390  }
1391 
1392  Result<VerifiedCandidate> FunctionalCandidate::check(const std::vector<BooleanFunction>& output_functions, const std::vector<std::vector<Gate*>>& registers)
1393  {
1394  switch (m_candidate_type)
1395  {
1396  case module_identification::CandidateType::equal:
1397  return check_equal(*this, output_functions);
1398  break;
1399  case module_identification::CandidateType::less_equal:
1400  return check_leq(*this, output_functions);
1401  break;
1402  case module_identification::CandidateType::addition:
1403  return check_add_sub(*this, output_functions, registers);
1404  break;
1405  case module_identification::CandidateType::addition_offset:
1406  return check_add_sub(*this, output_functions, registers);
1407  break;
1408  case module_identification::CandidateType::absolute:
1409  return check_absolute(*this, output_functions);
1410  break;
1411  case module_identification::CandidateType::value_check:
1412  return check_value_check(*this, output_functions);
1413  break;
1414  case module_identification::CandidateType::constant_multiplication:
1415  return check_constant_multiplication(*this, output_functions);
1416  break;
1417  case module_identification::CandidateType::constant_multiplication_offset:
1418  return check_constant_multiplication_offset(*this, output_functions);
1419  break;
1420  case module_identification::CandidateType::counter:
1421  return check_counter(*this, output_functions);
1422  break;
1423  default:
1424  break;
1425  }
1426  return ERR("No check function implemented for type" + enum_to_string(m_candidate_type));
1427  }
1428  } // namespace module_identification
1429 } // namespace hal
u32 size
This file contains the enumeration and constants for the candidate types used in the module identific...
static Result< BooleanFunction > Slt(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Eq(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Add(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Ule(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Sub(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Concat(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Ult(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static BooleanFunction Index(u16 index, u16 size)
static Result< BooleanFunction > Sle(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Slice(BooleanFunction &&p0, BooleanFunction &&p1, BooleanFunction &&p2, u16 size)
Value
represents the type of the node
static BooleanFunction Const(const BooleanFunction::Value &value)
static Result< BooleanFunction > Not(BooleanFunction &&p0, u16 size)
Definition: net.h:58
Represents a functional candidate derived from structural candidates.
std::map< std::string, std::map< std::string, std::map< std::string, std::map< std::string, u64 > > > > m_timings
void add_additional_data(std::string key, std::string value)
Add additional data to the functional candidate.
std::vector< std::vector< Net * > > m_operands
Represents a verified candidate for module identification.
uint64_t u64
Definition: defines.h:42
uint32_t u32
Definition: defines.h:41
This file contains the class and functions for handling functional candidates within the module ident...
#define log_error(channel,...)
Definition: log.h:78
#define ERR(message)
Definition: result.h:60
#define OK(...)
Definition: result.h:56
#define ERR_APPEND(prev_error, message)
Definition: result.h:64
std::vector< BooleanFunction::Value > Ite(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1, const std::vector< BooleanFunction::Value > &p2)
std::vector< BooleanFunction::Value > Add(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
std::vector< BooleanFunction::Value > Not(const std::vector< BooleanFunction::Value > &p)
std::vector< BooleanFunction::Value > Eq(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
void remove(std::filesystem::path file_path)
Result< VerifiedCandidate > check_equal(FunctionalCandidate &fc, const std::vector< BooleanFunction > &output_functions)
Result< VerifiedCandidate > check_leq(FunctionalCandidate &fc, const std::vector< BooleanFunction > &output_functions)
Result< VerifiedCandidate > check_add_sub_offset(FunctionalCandidate &fc, const std::vector< BooleanFunction > &output_functions, const std::vector< std::vector< Gate * >> &registers)
Result< VerifiedCandidate > check_absolute(FunctionalCandidate &fc, const std::vector< BooleanFunction > &output_functions)
Result< VerifiedCandidate > check_sub(FunctionalCandidate &fc, const std::vector< BooleanFunction > &output_functions, const std::vector< std::vector< Gate * >> &registers)
Result< VerifiedCandidate > check_sliced_add(FunctionalCandidate &fc, const std::vector< BooleanFunction > &output_functions)
Result< VerifiedCandidate > check_constant_multiplication(FunctionalCandidate &fc, const std::vector< BooleanFunction > &output_functions)
Result< VerifiedCandidate > check_addition(FunctionalCandidate &fc, const std::vector< BooleanFunction > &output_functions)
Result< VerifiedCandidate > check_add_sub(FunctionalCandidate &fc, const std::vector< BooleanFunction > &output_functions, const std::vector< std::vector< Gate * >> &registers)
Result< VerifiedCandidate > check_constant_multiplication_offset(FunctionalCandidate &fc, const std::vector< BooleanFunction > &output_functions)
Result< VerifiedCandidate > check_value_check(FunctionalCandidate &fc, const std::vector< BooleanFunction > &output_functions)
CandidateType
Enumeration of the different candidate types for module identification.
@ signed_less_equal
Signed less-than-or-equal comparison.
@ less_equal
Less-than-or-equal comparison.
@ signed_less_than
Signed less-than comparison.
Result< VerifiedCandidate > check_counter(FunctionalCandidate &fc, const std::vector< BooleanFunction > &output_functions)
Result< VerifiedCandidate > check_addition_offset(FunctionalCandidate &fc, const std::vector< BooleanFunction > &output_functions)
Definition: defines.h:45
std::string enum_to_string(T e)
Definition: enums.h:53
PinType type
Net * net
This file contains helper functions for module identification in the HAL framework.
The result of a module identification run containing the candidates.
Definition: result.h:55