Clearmatics Libff  0.1
C++ library for Finite Fields and Elliptic Curves
curve_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_CURVES_CURVE_SERIALIZATION_TCC__
10 #define __LIBFF_ALGEBRA_CURVES_CURVE_SERIALIZATION_TCC__
11 
12 #include "libff/algebra/curves/curve_serialization.hpp"
13 #include "libff/algebra/curves/curve_utils.hpp"
14 #include "libff/algebra/fields/field_serialization.hpp"
15 
16 namespace libff
17 {
18 
19 namespace internal
20 {
21 
22 // Generic class to implement group element read and write methods for various
23 // combinations of parameters. Expected to define at least methods:
24 //
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;
29 
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>
33 {
34 public:
35  static void write(const GroupT &group_el, std::ostream &out_s)
36  {
37  GroupT affine_p = group_el;
38  affine_p.to_affine_coordinates();
39  out_s << "[";
40  field_write<encoding_json, Form>(affine_p.X, out_s);
41  out_s << ",";
42  field_write<encoding_json, Form>(affine_p.Y, out_s);
43  out_s << "]";
44  }
45  static void read(GroupT &group_el, std::istream &in_s)
46  {
47  using base_field = typename std::decay<decltype(group_el.X)>::type;
48 
49  char sep;
50 
51  in_s >> sep;
52  if (sep != '[') {
53  throw std::runtime_error(
54  "expected opening bracket reading group element");
55  }
56  field_read<encoding_json, Form>(group_el.X, in_s);
57 
58  in_s >> sep;
59  if (sep != ',') {
60  throw std::runtime_error("expected comma reading group element");
61  }
62 
63  field_read<encoding_json, Form>(group_el.Y, in_s);
64  in_s >> sep;
65  if (sep != ']') {
66  throw std::runtime_error(
67  "expected closing bracket reading group element");
68  }
69 
70  if (group_el.X.is_zero() && (group_el.Y == base_field::one())) {
71  group_el.Z = group_el.Z.zero();
72  } else {
73  group_el.Z = group_el.Z.one();
74  }
75  }
76 };
77 
78 // Generic uncompressed binary encoding / decoding
79 template<form_t Form, typename GroupT>
80 class group_element_codec<encoding_binary, Form, compression_off, GroupT>
81 {
82 public:
83  static void write(const GroupT &group_el, std::ostream &out_s)
84  {
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);
89  }
90  static void read(GroupT &group_el, std::istream &in_s)
91  {
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();
97  } else {
98  group_el.Z = base_field::one();
99  }
100  }
101 };
102 
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()
107 //
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>
112 {
113 public:
114  static void write(const GroupT &group_el, std::ostream &out_s)
115  {
116  if (!group_el.is_zero()) {
117  GroupT affine(group_el);
118  affine.to_affine_coordinates();
119 
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);
124  } else {
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);
128  }
129  }
130  static void read(GroupT &group_el, std::istream &in_s)
131  {
132  using Fq = typename std::decay<decltype(group_el.X)>::type;
133 
134  mp_limb_t flags;
135  field_read_with_flags<encoding_binary, Form>(group_el.X, flags, in_s);
136  if (0 == (flags & 0x2)) {
137 
138 #ifdef DEBUG
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
145  Fq x = group_el.X;
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");
151  }
152 #endif // #ifdef DEBUG
153 
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;
159  }
160 
161  group_el.Z = Fq::one();
162  } else {
163  group_el = GroupT::zero();
164  }
165  }
166 };
167 
168 } // namespace internal
169 
170 template<encoding_t Enc, form_t Form, compression_t Comp, typename GroupT>
171 void group_read(GroupT &v, std::istream &in_s)
172 {
173  internal::group_element_codec<Enc, Form, Comp, GroupT>::read(v, in_s);
174 }
175 
176 template<encoding_t Enc, form_t Form, compression_t Comp, typename GroupT>
177 void group_write(const GroupT &v, std::ostream &out_s)
178 {
179  internal::group_element_codec<Enc, Form, Comp, GroupT>::write(v, out_s);
180 }
181 
182 } // namespace libff
183 
184 #endif // __LIBFF_ALGEBRA_CURVES_CURVE_SERIALIZATION_TCC__