2  *****************************************************************************
 
    4  Implementation of functions to sample BACS examples with prescribed parameters
 
    5  (according to some distribution).
 
    7  See bacs_examples.hpp .
 
    9  *****************************************************************************
 
   10  * @author     This file is part of libsnark, developed by SCIPR Lab
 
   11  *             and contributors (see AUTHORS).
 
   12  * @copyright  MIT license (see LICENSE file)
 
   13  *****************************************************************************/
 
   15 #ifndef BACS_EXAMPLES_TCC_
 
   16 #define BACS_EXAMPLES_TCC_
 
   19 #include <libff/common/utils.hpp>
 
   24 template<typename FieldT>
 
   25 linear_combination<FieldT> random_linear_combination(const size_t num_variables)
 
   27     const size_t terms = 1 + (std::rand() % 3);
 
   28     linear_combination<FieldT> result;
 
   30     for (size_t i = 0; i < terms; ++i) {
 
   32             FieldT(std::rand()); // TODO: replace with FieldT::random_element(),
 
   33                                  // when it becomes faster...
 
   35                  coeff * variable<FieldT>(std::rand() % (num_variables + 1));
 
   41 template<typename FieldT>
 
   42 bacs_example<FieldT> generate_bacs_example(
 
   43     const size_t primary_input_size,
 
   44     const size_t auxiliary_input_size,
 
   45     const size_t num_gates,
 
   46     const size_t num_outputs)
 
   48     bacs_example<FieldT> example;
 
   49     for (size_t i = 0; i < primary_input_size; ++i) {
 
   50         example.primary_input.emplace_back(FieldT::random_element());
 
   53     for (size_t i = 0; i < auxiliary_input_size; ++i) {
 
   54         example.auxiliary_input.emplace_back(FieldT::random_element());
 
   57     example.circuit.primary_input_size = primary_input_size;
 
   58     example.circuit.auxiliary_input_size = auxiliary_input_size;
 
   60     bacs_variable_assignment<FieldT> all_vals;
 
   63         example.primary_input.begin(),
 
   64         example.primary_input.end());
 
   67         example.auxiliary_input.begin(),
 
   68         example.auxiliary_input.end());
 
   70     for (size_t i = 0; i < num_gates; ++i) {
 
   71         const size_t num_variables =
 
   72             primary_input_size + auxiliary_input_size + i;
 
   73         bacs_gate<FieldT> gate;
 
   74         gate.lhs = random_linear_combination<FieldT>(num_variables);
 
   75         gate.rhs = random_linear_combination<FieldT>(num_variables);
 
   76         gate.output = variable<FieldT>(num_variables + 1);
 
   78         if (i >= num_gates - num_outputs) {
 
   79             /* make gate a circuit output and fix */
 
   80             gate.is_circuit_output = true;
 
   81             const var_index_t var_idx =
 
   83                 (1 + primary_input_size + std::min(num_gates - num_outputs, i));
 
   84             const FieldT var_val =
 
   85                 (var_idx == 0 ? FieldT::one() : all_vals[var_idx - 1]);
 
   87             if (std::rand() % 2 == 0) {
 
   88                 const FieldT lhs_val = gate.lhs.evaluate(all_vals);
 
   89                 const FieldT coeff = -(lhs_val * var_val.inverse());
 
   90                 gate.lhs = gate.lhs + coeff * variable<FieldT>(var_idx);
 
   92                 const FieldT rhs_val = gate.rhs.evaluate(all_vals);
 
   93                 const FieldT coeff = -(rhs_val * var_val.inverse());
 
   94                 gate.rhs = gate.rhs + coeff * variable<FieldT>(var_idx);
 
   97             assert(gate.evaluate(all_vals).is_zero());
 
   99             gate.is_circuit_output = false;
 
  102         example.circuit.add_gate(gate);
 
  103         all_vals.emplace_back(gate.evaluate(all_vals));
 
  106     assert(example.circuit.is_satisfied(
 
  107         example.primary_input, example.auxiliary_input));
 
  112 } // namespace libsnark
 
  114 #endif // BACS_EXAMPLES_TCC