2 *****************************************************************************
3 * @author This file is part of libff, developed by Clearmatics Ltd
4 * (originally developed by SCIPR Lab) and contributors
6 * @copyright MIT license (see LICENSE file)
7 *****************************************************************************/
9 #ifndef __LIBFF_ALGEBRA_FIELDS_FIELD_SERIALIZATION_TCC__
10 #define __LIBFF_ALGEBRA_FIELDS_FIELD_SERIALIZATION_TCC__
12 #include "libff/algebra/fields/fp.hpp"
13 #include "libff/algebra/serialization.hpp"
23 template<encoding_t Enc, form_t Form, typename FieldT>
24 class field_element_codec;
26 template<typename FieldT, form_t Form>
27 class field_element_codec<encoding_json, Form, FieldT>
30 // Convert a field element to JSON
31 static void write(const FieldT &field_el, std::ostream &out_s)
34 typename std::decay<decltype(field_el.coeffs[0])>::type;
36 // Note that we write components of extension fields
37 // highest-order-first.
39 size_t i = FieldT::tower_extension_degree - 1;
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);
51 // Read a field element from JSON
52 static void read(FieldT &field_el, std::istream &in_s)
55 typename std::decay<decltype(field_el.coeffs[0])>::type;
57 // Read opening '[' char, then each component (highest-order-first)
58 // separated by ',' char, then a closing ']' char.
63 throw std::runtime_error("expected opening bracket");
66 size_t i = FieldT::tower_extension_degree - 1;
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);
74 throw std::runtime_error("expected comma separator");
81 throw std::runtime_error("expected closing bracket");
86 // Implementation of field_element_codec<encoding_json, ...> for the base-case
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>>
92 using Field = libff::Fp_model<n, modulus>;
93 static void write(const Field &field_el, std::ostream &out_s)
95 if (Form == form_plain) {
96 out_s << '"' << bigint_to_hex(field_el.as_bigint(), true) << '"';
98 out_s << '"' << bigint_to_hex(field_el.mont_repr, true) << '"';
101 static void read(Field &field_el, std::istream &in_s)
106 throw std::runtime_error("expected json string");
108 std::string bigint_hex;
110 std::getline(in_s, bigint_hex, '"');
112 throw std::runtime_error("json string not terminated");
115 if (Form == form_plain) {
117 bigint_from_hex(plain, bigint_hex);
118 field_el = Field(plain);
120 bigint_from_hex(field_el.mont_repr, bigint_hex);
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>
130 static void write(const FieldT &field_el, std::ostream &out_s)
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);
139 static void read(FieldT &field_el, std::istream &in_s)
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);
148 static void write_with_flags(
149 const FieldT &field_el, const mp_limb_t flags, std::ostream &out_s)
152 typename std::decay<decltype(field_el.coeffs[0])>::type;
153 // Write first component with flags, then all remaining components as
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);
162 static void read_with_flags(
163 FieldT &field_el, mp_limb_t &flags, std::istream &in_s)
166 typename std::decay<decltype(field_el.coeffs[0])>::type;
167 // Read first component with flags, then all remaining components as
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);
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>>
184 using Field = libff::Fp_model<n, modulus>;
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;
191 static bool verify_flag_capacity()
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;
197 static void write(const Field &field_el, std::ostream &out_s)
199 // Convert to bigint, reverse bytes in-place, and write to stream.
201 if (Form == form_plain) {
202 bi = field_el.as_bigint();
204 bi = field_el.mont_repr;
206 std::reverse((char *)(&bi), (char *)(&bi + 1));
207 out_s.write((const char *)(&bi.data[0]), sizeof(bi));
209 static void read(Field &field_el, std::istream &in_s)
211 // Read bigint from stream, reverse bytes in-place and convert to field
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);
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));
224 static void write_with_flags(
225 const Field &field_el, const mp_limb_t flags, std::ostream &out_s)
227 assert(verify_flag_capacity());
228 assert(flags == (flags & ((1 << NUM_FLAG_BITS) - 1)));
230 if (Form == form_plain) {
231 bi = field_el.as_bigint();
233 bi = field_el.mont_repr;
236 assert((bi.data[n - 1] & VALUE_MASK) == bi.data[n - 1]);
237 bi.data[n - 1] = bi.data[n - 1] | (flags << FLAG_SHIFT);
239 std::reverse((char *)(&bi), (char *)(&bi + 1));
240 out_s.write((const char *)(&bi.data[0]), sizeof(bi));
242 static void read_with_flags(
243 Field &field_el, mp_limb_t &flags, std::istream &in_s)
245 assert(verify_flag_capacity());
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));
254 flags = res.data[n - 1] >> FLAG_SHIFT;
255 res.data[n - 1] = res.data[n - 1] & VALUE_MASK;
257 field_el = Field(res);
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));
263 flags = res.data[n - 1] >> FLAG_SHIFT;
264 res.data[n - 1] = res.data[n - 1] & VALUE_MASK;
269 } // namespace internal
271 template<typename BigIntT>
272 void bigint_from_hex(BigIntT &v, const std::string &hex)
274 hex_to_bytes_reversed(hex, &v.data[0], sizeof(v.data));
277 template<typename BigIntT>
278 std::string bigint_to_hex(const BigIntT &v, bool prefix)
280 return bytes_to_hex_reversed(&v.data[0], sizeof(v.data), prefix);
283 template<typename BigIntT>
284 void bigint_from_dec(BigIntT &v, const std::string &dec)
286 v = BigIntT(dec.c_str());
289 template<typename BigIntT> std::string bigint_to_dec(const BigIntT &v)
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);
300 template<encoding_t Enc, form_t Form, typename FieldT>
301 void field_read(FieldT &v, std::istream &in_s)
303 internal::field_element_codec<Enc, Form, FieldT>::read(v, in_s);
306 template<encoding_t Enc, form_t Form, typename FieldT>
307 void field_write(const FieldT &v, std::ostream &out_s)
309 internal::field_element_codec<Enc, Form, FieldT>::write(v, out_s);
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)
315 internal::field_element_codec<Enc, Form, FieldT>::read_with_flags(
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)
323 internal::field_element_codec<Enc, Form, FieldT>::write_with_flags(
329 #endif // __LIBFF_ALGEBRA_FIELDS_FIELD_SERIALIZATION_TCC__