Clearmatics Libff  0.1
C++ library for Finite Fields and Elliptic Curves
field_serialization.tcc
Go to the documentation of this file.
1 /** @file
2  *****************************************************************************
3  * @author This file is part of libff, developed by Clearmatics Ltd
4  * (originally developed by SCIPR Lab) and contributors
5  * (see AUTHORS).
6  * @copyright MIT license (see LICENSE file)
7  *****************************************************************************/
8 
9 #ifndef __LIBFF_ALGEBRA_FIELDS_FIELD_SERIALIZATION_TCC__
10 #define __LIBFF_ALGEBRA_FIELDS_FIELD_SERIALIZATION_TCC__
11 
12 #include "libff/algebra/fields/fp.hpp"
13 #include "libff/algebra/serialization.hpp"
14 
15 #include <algorithm>
16 
17 namespace libff
18 {
19 
20 namespace internal
21 {
22 
23 template<encoding_t Enc, form_t Form, typename FieldT>
24 class field_element_codec;
25 
26 template<typename FieldT, form_t Form>
27 class field_element_codec<encoding_json, Form, FieldT>
28 {
29 public:
30  // Convert a field element to JSON
31  static void write(const FieldT &field_el, std::ostream &out_s)
32  {
33  using base_field_t =
34  typename std::decay<decltype(field_el.coeffs[0])>::type;
35 
36  // Note that we write components of extension fields
37  // highest-order-first.
38  out_s << '[';
39  size_t i = FieldT::tower_extension_degree - 1;
40  do {
41  // out_s << field_element_to_json(field_el.coeffs[i]);
42  field_element_codec<encoding_json, Form, base_field_t>::write(
43  field_el.coeffs[i], out_s);
44  if (i > 0) {
45  out_s << ',';
46  }
47  } while (i-- > 0);
48  out_s << ']';
49  }
50 
51  // Read a field element from JSON
52  static void read(FieldT &field_el, std::istream &in_s)
53  {
54  using base_field_t =
55  typename std::decay<decltype(field_el.coeffs[0])>::type;
56 
57  // Read opening '[' char, then each component (highest-order-first)
58  // separated by ',' char, then a closing ']' char.
59 
60  char sep;
61  in_s >> sep;
62  if (sep != '[') {
63  throw std::runtime_error("expected opening bracket");
64  }
65 
66  size_t i = FieldT::tower_extension_degree - 1;
67  do {
68  field_element_codec<encoding_json, Form, base_field_t>::read(
69  field_el.coeffs[i], in_s);
70  // field_element_read_json(field_el.coeffs[i], in_s);
71  if (i > 0) {
72  in_s >> sep;
73  if (sep != ',') {
74  throw std::runtime_error("expected comma separator");
75  }
76  }
77  } while (i-- > 0);
78 
79  in_s >> sep;
80  if (sep != ']') {
81  throw std::runtime_error("expected closing bracket");
82  }
83  }
84 };
85 
86 // Implementation of field_element_codec<encoding_json, ...> for the base-case
87 // of Fp_model types.
88 template<mp_size_t n, const libff::bigint<n> &modulus, form_t Form>
89 class field_element_codec<encoding_json, Form, libff::Fp_model<n, modulus>>
90 {
91 public:
92  using Field = libff::Fp_model<n, modulus>;
93  static void write(const Field &field_el, std::ostream &out_s)
94  {
95  if (Form == form_plain) {
96  out_s << '"' << bigint_to_hex(field_el.as_bigint(), true) << '"';
97  } else {
98  out_s << '"' << bigint_to_hex(field_el.mont_repr, true) << '"';
99  }
100  };
101  static void read(Field &field_el, std::istream &in_s)
102  {
103  char quote;
104  in_s >> quote;
105  if (quote != '"') {
106  throw std::runtime_error("expected json string");
107  }
108  std::string bigint_hex;
109  try {
110  std::getline(in_s, bigint_hex, '"');
111  } catch (...) {
112  throw std::runtime_error("json string not terminated");
113  }
114 
115  if (Form == form_plain) {
116  bigint<n> plain;
117  bigint_from_hex(plain, bigint_hex);
118  field_el = Field(plain);
119  } else {
120  bigint_from_hex(field_el.mont_repr, bigint_hex);
121  }
122  }
123 };
124 
125 // Generic reader and write for fields and field extensions.
126 template<typename FieldT, form_t Form>
127 class field_element_codec<encoding_binary, Form, FieldT>
128 {
129 public:
130  static void write(const FieldT &field_el, std::ostream &out_s)
131  {
132  using base_field_t =
133  typename std::decay<decltype(field_el.coeffs[0])>::type;
134  for (size_t i = 0; i < FieldT::tower_extension_degree; ++i) {
135  field_element_codec<encoding_binary, Form, base_field_t>::write(
136  field_el.coeffs[i], out_s);
137  }
138  }
139  static void read(FieldT &field_el, std::istream &in_s)
140  {
141  using base_field_t =
142  typename std::decay<decltype(field_el.coeffs[0])>::type;
143  for (size_t i = 0; i < FieldT::tower_extension_degree; ++i) {
144  field_element_codec<encoding_binary, Form, base_field_t>::read(
145  field_el.coeffs[i], in_s);
146  }
147  }
148  static void write_with_flags(
149  const FieldT &field_el, const mp_limb_t flags, std::ostream &out_s)
150  {
151  using base_field_t =
152  typename std::decay<decltype(field_el.coeffs[0])>::type;
153  // Write first component with flags, then all remaining components as
154  // normal.
155  field_element_codec<encoding_binary, Form, base_field_t>::
156  write_with_flags(field_el.coeffs[0], flags, out_s);
157  for (size_t i = 1; i < FieldT::tower_extension_degree; ++i) {
158  field_element_codec<encoding_binary, Form, base_field_t>::write(
159  field_el.coeffs[i], out_s);
160  }
161  }
162  static void read_with_flags(
163  FieldT &field_el, mp_limb_t &flags, std::istream &in_s)
164  {
165  using base_field_t =
166  typename std::decay<decltype(field_el.coeffs[0])>::type;
167  // Read first component with flags, then all remaining components as
168  // normal.
169  field_element_codec<encoding_binary, Form, base_field_t>::
170  read_with_flags(field_el.coeffs[0], flags, in_s);
171  for (size_t i = 1; i < FieldT::tower_extension_degree; ++i) {
172  field_element_codec<encoding_binary, Form, base_field_t>::read(
173  field_el.coeffs[i], in_s);
174  }
175  }
176 };
177 
178 /// Implementation of field_element_bytes for the base-case of Fp_model types.
179 /// Big-endian bigint values (i.e. not in montgomery form).
180 template<mp_size_t n, const libff::bigint<n> &modulus, form_t Form>
181 class field_element_codec<encoding_binary, Form, libff::Fp_model<n, modulus>>
182 {
183 public:
184  using Field = libff::Fp_model<n, modulus>;
185 
186  static constexpr size_t NUM_FLAG_BITS = 2;
187  static constexpr size_t FLAG_SHIFT =
188  (8 * sizeof(mp_limb_t)) - NUM_FLAG_BITS;
189  static constexpr mp_limb_t VALUE_MASK = (((mp_limb_t)1) << FLAG_SHIFT) - 1;
190 
191  static bool verify_flag_capacity()
192  {
193  const size_t field_bits = Field::num_bits;
194  const size_t field_size_on_disk = 8 * sizeof(Field);
195  return (field_size_on_disk - field_bits) >= NUM_FLAG_BITS;
196  }
197  static void write(const Field &field_el, std::ostream &out_s)
198  {
199  // Convert to bigint, reverse bytes in-place, and write to stream.
200  libff::bigint<n> bi;
201  if (Form == form_plain) {
202  bi = field_el.as_bigint();
203  } else {
204  bi = field_el.mont_repr;
205  }
206  std::reverse((char *)(&bi), (char *)(&bi + 1));
207  out_s.write((const char *)(&bi.data[0]), sizeof(bi));
208  }
209  static void read(Field &field_el, std::istream &in_s)
210  {
211  // Read bigint from stream, reverse bytes in-place and convert to field
212  // element.
213  if (Form == form_plain) {
214  libff::bigint<n> res;
215  in_s.read((char *)(&res.data[0]), sizeof(res));
216  std::reverse((char *)(&res), (char *)(&res + 1));
217  field_el = Field(res);
218  } else {
219  libff::bigint<n> &res = field_el.mont_repr;
220  in_s.read((char *)(&res.data[0]), sizeof(res));
221  std::reverse((char *)(&res), (char *)(&res + 1));
222  }
223  }
224  static void write_with_flags(
225  const Field &field_el, const mp_limb_t flags, std::ostream &out_s)
226  {
227  assert(verify_flag_capacity());
228  assert(flags == (flags & ((1 << NUM_FLAG_BITS) - 1)));
229  libff::bigint<n> bi;
230  if (Form == form_plain) {
231  bi = field_el.as_bigint();
232  } else {
233  bi = field_el.mont_repr;
234  }
235 
236  assert((bi.data[n - 1] & VALUE_MASK) == bi.data[n - 1]);
237  bi.data[n - 1] = bi.data[n - 1] | (flags << FLAG_SHIFT);
238 
239  std::reverse((char *)(&bi), (char *)(&bi + 1));
240  out_s.write((const char *)(&bi.data[0]), sizeof(bi));
241  }
242  static void read_with_flags(
243  Field &field_el, mp_limb_t &flags, std::istream &in_s)
244  {
245  assert(verify_flag_capacity());
246 
247  // Read bigint from stream, reverse bytes in-place, extract flags and
248  // convert to field element.
249  if (Form == form_plain) {
250  libff::bigint<n> res;
251  in_s.read((char *)(&res.data[0]), sizeof(res));
252  std::reverse((char *)(&res), (char *)(&res + 1));
253 
254  flags = res.data[n - 1] >> FLAG_SHIFT;
255  res.data[n - 1] = res.data[n - 1] & VALUE_MASK;
256 
257  field_el = Field(res);
258  } else {
259  libff::bigint<n> &res = field_el.mont_repr;
260  in_s.read((char *)(&res.data[0]), sizeof(res));
261  std::reverse((char *)(&res), (char *)(&res + 1));
262 
263  flags = res.data[n - 1] >> FLAG_SHIFT;
264  res.data[n - 1] = res.data[n - 1] & VALUE_MASK;
265  }
266  }
267 };
268 
269 } // namespace internal
270 
271 template<typename BigIntT>
272 void bigint_from_hex(BigIntT &v, const std::string &hex)
273 {
274  hex_to_bytes_reversed(hex, &v.data[0], sizeof(v.data));
275 }
276 
277 template<typename BigIntT>
278 std::string bigint_to_hex(const BigIntT &v, bool prefix)
279 {
280  return bytes_to_hex_reversed(&v.data[0], sizeof(v.data), prefix);
281 }
282 
283 template<typename BigIntT>
284 void bigint_from_dec(BigIntT &v, const std::string &dec)
285 {
286  v = BigIntT(dec.c_str());
287 }
288 
289 template<typename BigIntT> std::string bigint_to_dec(const BigIntT &v)
290 {
291  const char *const fmt = "%Nd";
292  const size_t num_chars = gmp_snprintf(nullptr, 0, fmt, v.data, BigIntT::N);
293  std::string result(num_chars, '0');
294  // num_chars holds the number of characters, excluding the null terminator,
295  // but gmp_snprintf requires the number INCLUDING the terminator.
296  gmp_snprintf(&result[0], num_chars + 1, fmt, v.data, BigIntT::N);
297  return result;
298 }
299 
300 template<encoding_t Enc, form_t Form, typename FieldT>
301 void field_read(FieldT &v, std::istream &in_s)
302 {
303  internal::field_element_codec<Enc, Form, FieldT>::read(v, in_s);
304 }
305 
306 template<encoding_t Enc, form_t Form, typename FieldT>
307 void field_write(const FieldT &v, std::ostream &out_s)
308 {
309  internal::field_element_codec<Enc, Form, FieldT>::write(v, out_s);
310 }
311 
312 template<encoding_t Enc, form_t Form, typename FieldT>
313 void field_read_with_flags(FieldT &v, mp_limb_t &flags, std::istream &in_s)
314 {
315  internal::field_element_codec<Enc, Form, FieldT>::read_with_flags(
316  v, flags, in_s);
317 }
318 
319 template<encoding_t Enc, form_t Form, typename FieldT>
320 void field_write_with_flags(
321  const FieldT &v, mp_limb_t flags, std::ostream &out_s)
322 {
323  internal::field_element_codec<Enc, Form, FieldT>::write_with_flags(
324  v, flags, out_s);
325 }
326 
327 } // namespace libff
328 
329 #endif // __LIBFF_ALGEBRA_FIELDS_FIELD_SERIALIZATION_TCC__