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_CURVES_CURVE_SERIALIZATION_TCC__
10 #define __LIBFF_ALGEBRA_CURVES_CURVE_SERIALIZATION_TCC__
12 #include "libff/algebra/curves/curve_serialization.hpp"
13 #include "libff/algebra/curves/curve_utils.hpp"
14 #include "libff/algebra/fields/field_serialization.hpp"
22 // Generic class to implement group element read and write methods for various
23 // combinations of parameters. Expected to define at least methods:
25 // static void write(const GroupT &group_el, std::ostream &out_s);
26 // static void read(GroupT &group_el, std::istream &in_s);
27 template<encoding_t Enc, form_t Form, compression_t Comp, typename GroupT>
28 class group_element_codec;
30 // Json encoding/decoding. Supported only for compression_off.
31 template<form_t Form, typename GroupT>
32 class group_element_codec<encoding_json, Form, compression_off, GroupT>
35 static void write(const GroupT &group_el, std::ostream &out_s)
37 GroupT affine_p = group_el;
38 affine_p.to_affine_coordinates();
40 field_write<encoding_json, Form>(affine_p.X, out_s);
42 field_write<encoding_json, Form>(affine_p.Y, out_s);
45 static void read(GroupT &group_el, std::istream &in_s)
47 using base_field = typename std::decay<decltype(group_el.X)>::type;
53 throw std::runtime_error(
54 "expected opening bracket reading group element");
56 field_read<encoding_json, Form>(group_el.X, in_s);
60 throw std::runtime_error("expected comma reading group element");
63 field_read<encoding_json, Form>(group_el.Y, in_s);
66 throw std::runtime_error(
67 "expected closing bracket reading group element");
70 if (group_el.X.is_zero() && (group_el.Y == base_field::one())) {
71 group_el.Z = group_el.Z.zero();
73 group_el.Z = group_el.Z.one();
78 // Generic uncompressed binary encoding / decoding
79 template<form_t Form, typename GroupT>
80 class group_element_codec<encoding_binary, Form, compression_off, GroupT>
83 static void write(const GroupT &group_el, std::ostream &out_s)
85 GroupT affine_p = group_el;
86 affine_p.to_affine_coordinates();
87 field_write<encoding_binary, Form>(affine_p.X, out_s);
88 field_write<encoding_binary, Form>(affine_p.Y, out_s);
90 static void read(GroupT &group_el, std::istream &in_s)
92 using base_field = typename std::decay<decltype(group_el.X)>::type;
93 field_read<encoding_binary, Form>(group_el.X, in_s);
94 field_read<encoding_binary, Form>(group_el.Y, in_s);
95 if (group_el.X.is_zero() && group_el.Y == base_field::one()) {
96 group_el.Z = base_field::zero();
98 group_el.Z = base_field::one();
103 // Binary compressed encoding / decoding. The base field must allow for 2 flags
104 // bits to fit in the high-order limb:
105 // bit 0 (mask 0x1) : Lowest order bit of Y coord
106 // bit 1 (mask 0x2) : First 2 bits signify GroupT::zero()
108 // Note, we rely on the field_write_with_flags call to ensure capacity in the
109 // limb and to shift the flags to the appropriate place.
110 template<form_t Form, typename GroupT>
111 class group_element_codec<encoding_binary, Form, compression_on, GroupT>
114 static void write(const GroupT &group_el, std::ostream &out_s)
116 if (!group_el.is_zero()) {
117 GroupT affine(group_el);
118 affine.to_affine_coordinates();
120 const mp_limb_t flags =
121 field_get_component_0(affine.Y).mont_repr.data[0] & 1;
122 field_write_with_flags<encoding_binary, Form>(
123 affine.X, flags, out_s);
125 // Use Montgomery encoding, to avoid wasting time reducing.
126 field_write_with_flags<encoding_binary, form_montgomery>(
127 group_el.X, 0x2, out_s);
130 static void read(GroupT &group_el, std::istream &in_s)
132 using Fq = typename std::decay<decltype(group_el.X)>::type;
135 field_read_with_flags<encoding_binary, Form>(group_el.X, flags, in_s);
136 if (0 == (flags & 0x2)) {
139 // This check has efficiency penalty under normal
140 // execution, so we only enable it in debug for
141 // now. TODO: this is a temporary solution that needs to
142 // be fixed in the long term: see issues #55
143 // https://github.com/clearmatics/libff/issues/55 and #70
144 // https://github.com/clearmatics/libff/issues/70
146 Fq x_squared = x * x;
147 Fq x_cubed = x_squared * x;
148 Fq y_squared = x_cubed + (GroupT::coeff_a * x) + GroupT::coeff_b;
149 if ((y_squared ^ Fq::euler) != Fq::one()) {
150 throw std::runtime_error("curve eqn has no solution at x");
152 #endif // #ifdef DEBUG
154 group_el.Y = curve_point_y_at_x<GroupT>(group_el.X);
155 const mp_limb_t Y_lsb =
156 field_get_component_0(group_el.Y).mont_repr.data[0] & 1;
157 if ((flags & 1) != Y_lsb) {
158 group_el.Y = -group_el.Y;
161 group_el.Z = Fq::one();
163 group_el = GroupT::zero();
168 } // namespace internal
170 template<encoding_t Enc, form_t Form, compression_t Comp, typename GroupT>
171 void group_read(GroupT &v, std::istream &in_s)
173 internal::group_element_codec<Enc, Form, Comp, GroupT>::read(v, in_s);
176 template<encoding_t Enc, form_t Form, compression_t Comp, typename GroupT>
177 void group_write(const GroupT &v, std::ostream &out_s)
179 internal::group_element_codec<Enc, Form, Comp, GroupT>::write(v, out_s);
184 #endif // __LIBFF_ALGEBRA_CURVES_CURVE_SERIALIZATION_TCC__