1 // Copyright (c) 2015-2022 Clearmatics Technologies Ltd
 
    3 // SPDX-License-Identifier: LGPL-3.0+
 
    5 #ifndef __ZETH_SERIALIZATION_R1CS_SERIALIZATION_TCC__
 
    6 #define __ZETH_SERIALIZATION_R1CS_SERIALIZATION_TCC__
 
    8 #include "libzeth/core/field_element_utils.hpp"
 
    9 #include "libzeth/core/group_element_utils.hpp"
 
   10 #include "libzeth/serialization/r1cs_serialization.hpp"
 
   11 #include "libzeth/serialization/stream_utils.hpp"
 
   19 template<typename FieldT>
 
   20 void constraints_write_json(
 
   21     const libsnark::linear_combination<FieldT> &constraints,
 
   26     for (const libsnark::linear_term<FieldT> < : constraints.terms) {
 
   32         out_s << "\"index\":" << lt.index << ",";
 
   34               << "\"" + base_field_element_to_hex(lt.coeff) << "\"";
 
   41 } // namespace internal
 
   43 template<typename FieldT>
 
   44 std::ostream &primary_inputs_write_json(
 
   45     const std::vector<FieldT> &public_inputs, std::ostream &out_s)
 
   48     for (size_t i = 0; i < public_inputs.size(); ++i) {
 
   49         out_s << field_element_to_json(public_inputs[i]);
 
   50         if (i < public_inputs.size() - 1) {
 
   58 template<typename FieldT>
 
   59 std::istream &primary_inputs_read_json(
 
   60     std::vector<FieldT> &public_inputs, std::istream &in_s)
 
   65         if ('[' != separator && ',' != separator) {
 
   70         field_element_read_json(element, in_s);
 
   71         public_inputs.push_back(element);
 
   76 template<typename ppT>
 
   77 std::string accumulation_vector_to_json(
 
   78     const libsnark::accumulation_vector<libff::G1<ppT>> &acc_vector)
 
   81     unsigned vect_length = acc_vector.rest.indices.size() + 1;
 
   82     ss << "[" << group_element_to_json(acc_vector.first);
 
   83     for (size_t i = 0; i < vect_length - 1; ++i) {
 
   84         ss << ", " << group_element_to_json(acc_vector.rest.values[i]);
 
   87     std::string vect_json_str = ss.str();
 
   92 template<typename ppT>
 
   93 libsnark::accumulation_vector<libff::G1<ppT>> accumulation_vector_from_json(
 
   94     const std::string &acc_vector_str)
 
   96     static const char prefix[] = "[\"";
 
   97     static const char suffix[] = "\"]";
 
   99     if (acc_vector_str.length() < (sizeof(prefix) - 1 + sizeof(suffix) - 1)) {
 
  100         throw std::invalid_argument("invalid accumulation vector string");
 
  103     size_t start_idx = acc_vector_str.find(prefix);
 
  104     if (start_idx == std::string::npos) {
 
  105         throw std::invalid_argument("invalid accumulation vector string");
 
  108     // TODO: Remove the temporary string.
 
  110     // Allocate once and reuse.
 
  111     std::string element_str;
 
  113     // Extract first element
 
  114     size_t end_idx = acc_vector_str.find(suffix, start_idx);
 
  115     if (end_idx == std::string::npos) {
 
  116         throw std::invalid_argument("invalid accumulation vector string");
 
  119     // Extract the string '["....", "...."]'
 
  123     element_str = acc_vector_str.substr(start_idx, end_idx + 2 - start_idx);
 
  124     libff::G1<ppT> front = group_element_from_json<libff::G1<ppT>>(element_str);
 
  125     start_idx = acc_vector_str.find(prefix, end_idx);
 
  127     // Extract remaining elements
 
  128     std::vector<libff::G1<ppT>> rest;
 
  130         end_idx = acc_vector_str.find(suffix, start_idx);
 
  131         if (end_idx == std::string::npos) {
 
  132             throw std::invalid_argument("invalid accumulation vector string");
 
  135         element_str = acc_vector_str.substr(start_idx, end_idx + 2 - start_idx);
 
  136         rest.push_back(group_element_from_json<libff::G1<ppT>>(element_str));
 
  137         start_idx = acc_vector_str.find(prefix, end_idx);
 
  138     } while (start_idx != std::string::npos);
 
  140     return libsnark::accumulation_vector<libff::G1<ppT>>(
 
  141         std::move(front), std::move(rest));
 
  144 template<typename FieldT>
 
  145 std::ostream &r1cs_write_json(
 
  146     const libsnark::r1cs_constraint_system<FieldT> &r1cs, std::ostream &out_s)
 
  148     // output inputs, right now need to compile with debug flag so that the
 
  149     // `variable_annotations` exists. Having trouble setting that up so will
 
  153     out_s << "\"scalar_field_characteristic\":"
 
  154           << "\"" + libff::bigint_to_hex(FieldT::field_char(), true) << "\",\n";
 
  155     out_s << "\"num_variables\":" << r1cs.num_variables() << ",\n";
 
  156     out_s << "\"num_constraints\":" << r1cs.num_constraints() << ",\n";
 
  157     out_s << "\"num_inputs\": " << r1cs.num_inputs() << ",\n";
 
  158     out_s << "\"variables_annotations\":[";
 
  159     for (size_t i = 0; i < r1cs.num_variables(); ++i) {
 
  161         out_s << "\"index\":" << i << ",";
 
  162         out_s << "\"annotation\":"
 
  163               << "\"" << r1cs.variable_annotations.at(i).c_str() << "\"";
 
  164         if (i == r1cs.num_variables() - 1) {
 
  171     out_s << "\"constraints\":[";
 
  172     for (size_t c = 0; c < r1cs.num_constraints(); ++c) {
 
  174         out_s << "\"constraint_id\": " << c << ",";
 
  175         out_s << "\"constraint_annotation\": "
 
  176               << "\"" << r1cs.constraint_annotations.at(c).c_str() << "\",";
 
  177         out_s << "\"linear_combination\":";
 
  180         internal::constraints_write_json(r1cs.constraints[c].a, out_s);
 
  183         internal::constraints_write_json(r1cs.constraints[c].b, out_s);
 
  186         internal::constraints_write_json(r1cs.constraints[c].c, out_s);
 
  188         if (c == r1cs.num_constraints() - 1) {
 
  199 template<typename FieldT>
 
  200 void linear_combination_read_bytes(
 
  201     libsnark::linear_combination<FieldT> &linear_combination,
 
  204     const uint32_t num_terms = read_bytes<uint32_t>(in_s);
 
  206     linear_combination.terms.clear();
 
  207     linear_combination.terms.reserve(num_terms);
 
  208     for (uint32_t i = 0; i < num_terms; ++i) {
 
  209         const libsnark::var_index_t idx =
 
  210             read_bytes<libsnark::var_index_t>(in_s);
 
  212         field_element_read_bytes(coeff, in_s);
 
  213         linear_combination.terms.emplace_back(idx, coeff);
 
  217 template<typename FieldT>
 
  218 void linear_combination_write_bytes(
 
  219     const libsnark::linear_combination<FieldT> &linear_combination,
 
  222     // Write the number of terms as a uint32_t to save space. If this assert
 
  223     // fires (a single linear combination contains 2^32 terms), change to
 
  226         linear_combination.terms.size() <=
 
  227         (size_t)std::numeric_limits<uint32_t>::max);
 
  228     const uint32_t num_terms = (uint32_t)linear_combination.terms.size();
 
  229     write_bytes(num_terms, out_s);
 
  231     for (const libsnark::linear_term<FieldT> &term : linear_combination.terms) {
 
  232         write_bytes(term.index, out_s);
 
  233         field_element_write_bytes(term.coeff, out_s);
 
  237 template<typename FieldT>
 
  238 void r1cs_constraint_read_bytes(
 
  239     libsnark::r1cs_constraint<FieldT> &constraint, std::istream &in_s)
 
  241     linear_combination_read_bytes(constraint.a, in_s);
 
  242     linear_combination_read_bytes(constraint.b, in_s);
 
  243     linear_combination_read_bytes(constraint.c, in_s);
 
  246 template<typename FieldT>
 
  247 void r1cs_constraint_write_bytes(
 
  248     const libsnark::r1cs_constraint<FieldT> &constraint, std::ostream &out_s)
 
  250     linear_combination_write_bytes(constraint.a, out_s);
 
  251     linear_combination_write_bytes(constraint.b, out_s);
 
  252     linear_combination_write_bytes(constraint.c, out_s);
 
  255 template<typename FieldT>
 
  256 void r1cs_read_bytes(
 
  257     libsnark::r1cs_constraint_system<FieldT> &r1cs, std::istream &in_s)
 
  259     read_bytes(r1cs.primary_input_size, in_s);
 
  260     read_bytes(r1cs.auxiliary_input_size, in_s);
 
  261     collection_read_bytes<
 
  262         std::vector<libsnark::r1cs_constraint<FieldT>>,
 
  263         r1cs_constraint_read_bytes>(r1cs.constraints, in_s);
 
  266 template<typename FieldT>
 
  267 void r1cs_write_bytes(
 
  268     const libsnark::r1cs_constraint_system<FieldT> &r1cs, std::ostream &out_s)
 
  270     write_bytes(r1cs.primary_input_size, out_s);
 
  271     write_bytes(r1cs.auxiliary_input_size, out_s);
 
  272     collection_write_bytes<
 
  273         std::vector<libsnark::r1cs_constraint<FieldT>>,
 
  274         r1cs_constraint_write_bytes>(r1cs.constraints, out_s);
 
  277 } // namespace libzeth
 
  279 #endif // __ZETH_SERIALIZATION_R1CS_SERIALIZATION_TCC__