Zeth - Zerocash on Ethereum  0.8
Reference implementation of the Zeth protocol by Clearmatics
r1cs_serialization.tcc
Go to the documentation of this file.
1 // Copyright (c) 2015-2022 Clearmatics Technologies Ltd
2 //
3 // SPDX-License-Identifier: LGPL-3.0+
4 
5 #ifndef __ZETH_SERIALIZATION_R1CS_SERIALIZATION_TCC__
6 #define __ZETH_SERIALIZATION_R1CS_SERIALIZATION_TCC__
7 
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"
12 
13 namespace libzeth
14 {
15 
16 namespace internal
17 {
18 
19 template<typename FieldT>
20 void constraints_write_json(
21  const libsnark::linear_combination<FieldT> &constraints,
22  std::ostream &out_s)
23 {
24  out_s << "[";
25  size_t count = 0;
26  for (const libsnark::linear_term<FieldT> &lt : constraints.terms) {
27  if (count != 0) {
28  out_s << ",";
29  }
30 
31  out_s << "{";
32  out_s << "\"index\":" << lt.index << ",";
33  out_s << "\"value\":"
34  << "\"" + base_field_element_to_hex(lt.coeff) << "\"";
35  out_s << "}";
36  count++;
37  }
38  out_s << "]";
39 }
40 
41 } // namespace internal
42 
43 template<typename FieldT>
44 std::ostream &primary_inputs_write_json(
45  const std::vector<FieldT> &public_inputs, std::ostream &out_s)
46 {
47  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) {
51  out_s << ",";
52  }
53  }
54  out_s << "]";
55  return out_s;
56 }
57 
58 template<typename FieldT>
59 std::istream &primary_inputs_read_json(
60  std::vector<FieldT> &public_inputs, std::istream &in_s)
61 {
62  while (true) {
63  char separator = 0;
64  in_s >> separator;
65  if ('[' != separator && ',' != separator) {
66  break;
67  }
68 
69  FieldT element;
70  field_element_read_json(element, in_s);
71  public_inputs.push_back(element);
72  };
73  return in_s;
74 }
75 
76 template<typename ppT>
77 std::string accumulation_vector_to_json(
78  const libsnark::accumulation_vector<libff::G1<ppT>> &acc_vector)
79 {
80  std::stringstream ss;
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]);
85  }
86  ss << "]";
87  std::string vect_json_str = ss.str();
88 
89  return vect_json_str;
90 }
91 
92 template<typename ppT>
93 libsnark::accumulation_vector<libff::G1<ppT>> accumulation_vector_from_json(
94  const std::string &acc_vector_str)
95 {
96  static const char prefix[] = "[\"";
97  static const char suffix[] = "\"]";
98 
99  if (acc_vector_str.length() < (sizeof(prefix) - 1 + sizeof(suffix) - 1)) {
100  throw std::invalid_argument("invalid accumulation vector string");
101  }
102 
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");
106  }
107 
108  // TODO: Remove the temporary string.
109 
110  // Allocate once and reuse.
111  std::string element_str;
112 
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");
117  }
118 
119  // Extract the string '["....", "...."]'
120  // ^ ^
121  // start_idx end_idx
122 
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);
126 
127  // Extract remaining elements
128  std::vector<libff::G1<ppT>> rest;
129  do {
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");
133  }
134 
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);
139 
140  return libsnark::accumulation_vector<libff::G1<ppT>>(
141  std::move(front), std::move(rest));
142 }
143 
144 template<typename FieldT>
145 std::ostream &r1cs_write_json(
146  const libsnark::r1cs_constraint_system<FieldT> &r1cs, std::ostream &out_s)
147 {
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
150  // leave for now.
151 
152  out_s << "{\n";
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) {
160  out_s << "{";
161  out_s << "\"index\":" << i << ",";
162  out_s << "\"annotation\":"
163  << "\"" << r1cs.variable_annotations.at(i).c_str() << "\"";
164  if (i == r1cs.num_variables() - 1) {
165  out_s << "}";
166  } else {
167  out_s << "},";
168  }
169  }
170  out_s << "],\n";
171  out_s << "\"constraints\":[";
172  for (size_t c = 0; c < r1cs.num_constraints(); ++c) {
173  out_s << "{";
174  out_s << "\"constraint_id\": " << c << ",";
175  out_s << "\"constraint_annotation\": "
176  << "\"" << r1cs.constraint_annotations.at(c).c_str() << "\",";
177  out_s << "\"linear_combination\":";
178  out_s << "{";
179  out_s << "\"A\":";
180  internal::constraints_write_json(r1cs.constraints[c].a, out_s);
181  out_s << ",";
182  out_s << "\"B\":";
183  internal::constraints_write_json(r1cs.constraints[c].b, out_s);
184  out_s << ",";
185  out_s << "\"C\":";
186  internal::constraints_write_json(r1cs.constraints[c].c, out_s);
187  out_s << "}";
188  if (c == r1cs.num_constraints() - 1) {
189  out_s << "}";
190  } else {
191  out_s << "},";
192  }
193  }
194  out_s << "]\n";
195  out_s << "}";
196  return out_s;
197 }
198 
199 template<typename FieldT>
200 void linear_combination_read_bytes(
201  libsnark::linear_combination<FieldT> &linear_combination,
202  std::istream &in_s)
203 {
204  const uint32_t num_terms = read_bytes<uint32_t>(in_s);
205 
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);
211  FieldT coeff;
212  field_element_read_bytes(coeff, in_s);
213  linear_combination.terms.emplace_back(idx, coeff);
214  }
215 }
216 
217 template<typename FieldT>
218 void linear_combination_write_bytes(
219  const libsnark::linear_combination<FieldT> &linear_combination,
220  std::ostream &out_s)
221 {
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
224  // size_t.
225  assert(
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);
230 
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);
234  }
235 }
236 
237 template<typename FieldT>
238 void r1cs_constraint_read_bytes(
239  libsnark::r1cs_constraint<FieldT> &constraint, std::istream &in_s)
240 {
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);
244 }
245 
246 template<typename FieldT>
247 void r1cs_constraint_write_bytes(
248  const libsnark::r1cs_constraint<FieldT> &constraint, std::ostream &out_s)
249 {
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);
253 }
254 
255 template<typename FieldT>
256 void r1cs_read_bytes(
257  libsnark::r1cs_constraint_system<FieldT> &r1cs, std::istream &in_s)
258 {
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);
264 }
265 
266 template<typename FieldT>
267 void r1cs_write_bytes(
268  const libsnark::r1cs_constraint_system<FieldT> &r1cs, std::ostream &out_s)
269 {
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);
275 }
276 
277 } // namespace libzeth
278 
279 #endif // __ZETH_SERIALIZATION_R1CS_SERIALIZATION_TCC__