algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp
Go to the documentation of this file.
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2020-2021 Mikhail Komarov <nemo@nil.foundation>
3 // Copyright (c) 2020-2021 Ilias Khairullin <ilias@nil.foundation>
4 //
5 // MIT License
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy
8 // of this software and associated documentation files (the "Software"), to deal
9 // in the Software without restriction, including without limitation the rights
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 // copies of the Software, and to permit persons to whom the Software is
12 // furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in all
15 // copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 // SOFTWARE.
24 //---------------------------------------------------------------------------//
25 
26 #ifndef CRYPTO3_MARSHALLING_ALGEBRA_CURVES_HPP
27 #define CRYPTO3_MARSHALLING_ALGEBRA_CURVES_HPP
28 
30 
31 #include <nil/crypto3/multiprecision/cpp_int.hpp>
32 
33 #include <boost/concept/assert.hpp>
34 
35 #include <iterator>
36 
37 namespace nil {
38  namespace marshalling {
39 
40  using namespace nil::crypto3;
41 
42  template<typename CurveType>
44 
45  // ZCash serialization format for BLS12-381
46  // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-09#appendix-C
47  template<>
50 
51  typedef typename curve_type::template g1_type<>::value_type g1_value_type;
52  typedef typename curve_type::template g2_type<>::value_type g2_value_type;
53 
54  typedef typename curve_type::template g1_type<algebra::curves::coordinates::affine>::value_type
56  typedef typename curve_type::template g2_type<algebra::curves::coordinates::affine>::value_type
58 
59  typedef typename g1_value_type::field_type::value_type g1_field_value_type;
60  typedef typename g2_value_type::field_type::value_type g2_field_value_type;
61 
62  typedef typename g1_field_value_type::integral_type integral_type;
63 
64  constexpr static const unsigned sizeof_field_element = 48;
65  typedef std::array<std::uint8_t, sizeof_field_element> compressed_g1_octets;
66  typedef std::array<std::uint8_t, 2 * sizeof_field_element> uncompressed_g1_octets;
67  typedef std::array<std::uint8_t, 2 * sizeof_field_element> compressed_g2_octets;
68  typedef std::array<std::uint8_t, 4 * sizeof_field_element> uncompressed_g2_octets;
69 
70  // Serialization procedure according to
71  // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-09#appendix-C.1
73  compressed_g1_octets result = {0};
74  g1_affine_value_type point_affine = point.to_affine();
75  auto m_byte = evaluate_m_byte(point, point_affine, true);
76  // TODO: check possibilities for TA
77  if (!(I_bit & m_byte)) {
78  multiprecision::export_bits(
79  point_affine.X.data.template convert_to<integral_type>(), result.rbegin(), 8, false);
80  }
81  result[0] |= m_byte;
82  return result;
83  }
84 
86  uncompressed_g1_octets result = {0};
87  g1_affine_value_type point_affine = point.to_affine();
88  auto m_byte = evaluate_m_byte(point, point_affine, false);
89  // TODO: check possibilities for TA
90  if (!(I_bit & m_byte)) {
91  multiprecision::export_bits(
92  point_affine.Y.data.template convert_to<integral_type>(), result.rbegin(), 8, false);
93  multiprecision::export_bits(point_affine.X.data.template convert_to<integral_type>(),
94  result.rbegin() + sizeof_field_element,
95  8,
96  false);
97  }
98  result[0] |= m_byte;
99  return result;
100  }
101 
103  compressed_g2_octets result = {0};
104  g2_affine_value_type point_affine = point.to_affine();
105  auto m_byte = evaluate_m_byte(point, point_affine, true);
106  // TODO: check possibilities for TA
107  if (!(I_bit & m_byte)) {
108  multiprecision::export_bits(
109  point_affine.X.data[0].data.template convert_to<integral_type>(), result.rbegin(), 8, false);
110  multiprecision::export_bits(point_affine.X.data[1].data.template convert_to<integral_type>(),
111  result.rbegin() + sizeof_field_element,
112  8,
113  false);
114  }
115  result[0] |= m_byte;
116  return result;
117  }
118 
120  uncompressed_g2_octets result = {0};
121  g2_affine_value_type point_affine = point.to_affine();
122  auto m_byte = evaluate_m_byte(point, point_affine, false);
123  // TODO: check possibilities for TA
124  if (!(I_bit & m_byte)) {
125  multiprecision::export_bits(
126  point_affine.Y.data[0].data.template convert_to<integral_type>(), result.rbegin(), 8, false);
127  multiprecision::export_bits(point_affine.Y.data[1].data.template convert_to<integral_type>(),
128  result.rbegin() + sizeof_field_element,
129  8,
130  false);
131  multiprecision::export_bits(point_affine.X.data[0].data.template convert_to<integral_type>(),
132  result.rbegin() + 2 * sizeof_field_element,
133  8,
134  false);
135  multiprecision::export_bits(point_affine.X.data[1].data.template convert_to<integral_type>(),
136  result.rbegin() + 3 * sizeof_field_element,
137  8,
138  false);
139  }
140  result[0] |= m_byte;
141  return result;
142  }
143 
144  // TODO: use iterators
145  // Deserialization procedure according to
146  // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-09#appendix-C.2
147  template<typename PointOctetsRange,
148  typename = typename std::enable_if<
149  std::is_same<std::uint8_t, typename PointOctetsRange::value_type>::value>::type>
150  static inline g1_value_type octets_to_g1_point(const PointOctetsRange &octets) {
151  BOOST_CONCEPT_ASSERT((boost::SinglePassRangeConcept<PointOctetsRange>));
152 
153  const std::uint8_t m_byte = *octets.begin() & 0xE0;
154  BOOST_ASSERT(m_byte != 0x20 && m_byte != 0x60 && m_byte != 0xE0);
155 
156  PointOctetsRange point_octets;
157  std::copy(octets.begin(), octets.end(), point_octets.begin());
158  *point_octets.begin() &= 0x1F;
159 
160  if (m_byte & C_bit) {
161  return compressed_to_g1_point(point_octets, m_byte);
162  }
163  return uncompressed_to_g1_point(point_octets, m_byte);
164  }
165 
166  // TODO: use iterators
167  template<typename PointOctetsRange,
168  typename = typename std::enable_if<
169  std::is_same<std::uint8_t, typename PointOctetsRange::value_type>::value>::type>
170  static inline g2_value_type octets_to_g2_point(const PointOctetsRange &octets) {
171  BOOST_CONCEPT_ASSERT((boost::SinglePassRangeConcept<PointOctetsRange>));
172 
173  const std::uint8_t m_byte = *octets.begin() & 0xE0;
174  BOOST_ASSERT(m_byte != 0x20 && m_byte != 0x60 && m_byte != 0xE0);
175 
176  PointOctetsRange point_octets;
177  std::copy(octets.begin(), octets.end(), point_octets.begin());
178  *point_octets.begin() &= 0x1F;
179 
180  if (m_byte & C_bit) {
181  return compressed_to_g2_point(point_octets, m_byte);
182  }
183  return uncompressed_to_g2_point(point_octets, m_byte);
184  }
185 
186  protected:
187  constexpr static const std::uint8_t C_bit = 0x80;
188  constexpr static const std::uint8_t I_bit = 0x40;
189  constexpr static const std::uint8_t S_bit = 0x20;
190  // constexpr static const typename g1_field_value_type::integral_type half_p =
191  // (g1_field_value_type::modulus - integral_type(1)) / integral_type(2);
192 
193  template<typename PointOctetsRange,
194  typename = typename std::enable_if<
195  std::is_same<std::uint8_t, typename PointOctetsRange::value_type>::value>::type>
196  static inline g1_value_type compressed_to_g1_point(PointOctetsRange &point_octets, std::uint8_t m_byte) {
197  BOOST_ASSERT(std::distance(point_octets.begin(), point_octets.end()) == sizeof_field_element);
198 
199  if (m_byte & I_bit) {
200  BOOST_ASSERT(point_octets.end() == std::find(point_octets.begin(), point_octets.end(), true));
201  return g1_value_type(); // point at infinity
202  }
203 
204  integral_type x;
205  multiprecision::import_bits(x, point_octets.rbegin(), point_octets.rend(), 8, false);
206  g1_field_value_type x_mod(x);
207  g1_field_value_type y2_mod = x_mod.pow(3) + g1_field_value_type(4);
208  BOOST_ASSERT(y2_mod.is_square());
209  g1_field_value_type y_mod = y2_mod.sqrt();
210  bool Y_bit = sign_gf_p(y_mod);
211  if (Y_bit == bool(m_byte & S_bit)) {
212  g1_value_type result(x_mod, y_mod, g1_field_value_type::one());
213  BOOST_ASSERT(result.is_well_formed());
214  return result;
215  }
216  g1_value_type result(x_mod, -y_mod, g1_field_value_type::one());
217  BOOST_ASSERT(result.is_well_formed());
218  return result;
219  }
220 
221  template<typename PointOctetsRange,
222  typename = typename std::enable_if<
223  std::is_same<std::uint8_t, typename PointOctetsRange::value_type>::value>::type>
224  static inline g1_value_type uncompressed_to_g1_point(PointOctetsRange &point_octets, std::uint8_t m_byte) {
225  BOOST_ASSERT(std::distance(point_octets.begin(), point_octets.end()) == 2 * sizeof_field_element);
226 
227  if (m_byte & I_bit) {
228  BOOST_ASSERT(point_octets.end() == std::find(point_octets.begin(), point_octets.end(), true));
229  return g1_value_type(); // point at infinity
230  }
231 
232  integral_type x, y;
233  multiprecision::import_bits(
234  y, point_octets.rbegin(), point_octets.rbegin() + sizeof_field_element, 8, false);
235  multiprecision::import_bits(
236  x, point_octets.rbegin() + sizeof_field_element, point_octets.rend(), 8, false);
237  g1_value_type result(g1_field_value_type(x), g1_field_value_type(y), g1_field_value_type::one());
238  BOOST_ASSERT(result.is_well_formed());
239  return result;
240  }
241 
242  template<typename PointOctetsRange,
243  typename = typename std::enable_if<
244  std::is_same<std::uint8_t, typename PointOctetsRange::value_type>::value>::type>
245  static inline g2_value_type compressed_to_g2_point(PointOctetsRange &point_octets, std::uint8_t m_byte) {
246  BOOST_ASSERT(std::distance(point_octets.begin(), point_octets.end()) == 2 * sizeof_field_element);
247 
248  if (m_byte & I_bit) {
249  BOOST_ASSERT(point_octets.end() == std::find(point_octets.begin(), point_octets.end(), true));
250  return g2_value_type(); // point at infinity
251  }
252 
253  integral_type x_0, x_1;
254  multiprecision::import_bits(
255  x_0, point_octets.rbegin(), point_octets.rbegin() + sizeof_field_element, 8, false);
256  multiprecision::import_bits(
257  x_1, point_octets.rbegin() + sizeof_field_element, point_octets.rend(), 8, false);
258  g2_field_value_type x_mod(x_0, x_1);
259  g2_field_value_type y2_mod = x_mod.pow(3) + g2_field_value_type(4, 4);
260  BOOST_ASSERT(y2_mod.is_square());
261  g2_field_value_type y_mod = y2_mod.sqrt();
262  bool Y_bit = sign_gf_p(y_mod);
263  if (Y_bit == bool(m_byte & S_bit)) {
264  g2_value_type result(x_mod, y_mod, g2_field_value_type::one());
265  BOOST_ASSERT(result.is_well_formed());
266  return result;
267  }
268  g2_value_type result(x_mod, -y_mod, g2_field_value_type::one());
269  BOOST_ASSERT(result.is_well_formed());
270  return result;
271  }
272 
273  template<typename PointOctetsRange,
274  typename = typename std::enable_if<
275  std::is_same<std::uint8_t, typename PointOctetsRange::value_type>::value>::type>
276  static inline g2_value_type uncompressed_to_g2_point(PointOctetsRange &point_octets, std::uint8_t m_byte) {
277  BOOST_ASSERT(std::distance(point_octets.begin(), point_octets.end()) == 4 * sizeof_field_element);
278 
279  if (m_byte & I_bit) {
280  BOOST_ASSERT(point_octets.end() == std::find(point_octets.begin(), point_octets.end(), true));
281  return g2_value_type(); // point at infinity
282  }
283 
284  integral_type x_0, x_1, y_0, y_1;
285  multiprecision::import_bits(
286  y_0, point_octets.rbegin(), point_octets.rbegin() + sizeof_field_element, 8, false);
287  multiprecision::import_bits(y_1,
288  point_octets.rbegin() + sizeof_field_element,
289  point_octets.rbegin() + 2 * sizeof_field_element,
290  8,
291  false);
292  multiprecision::import_bits(x_0,
293  point_octets.rbegin() + 2 * sizeof_field_element,
294  point_octets.rbegin() + 3 * sizeof_field_element,
295  8,
296  false);
297  multiprecision::import_bits(
298  x_1, point_octets.rbegin() + 3 * sizeof_field_element, point_octets.rend(), 8, false);
301  g2_field_value_type::one());
302  BOOST_ASSERT(result.is_well_formed());
303  return result;
304  }
305 
306  static inline bool sign_gf_p(const g1_field_value_type &v) {
307  static const typename g1_field_value_type::integral_type half_p =
308  (g1_field_value_type::modulus - integral_type(1)) / integral_type(2);
309 
310  if (v > half_p) {
311  return true;
312  }
313  return false;
314  }
315 
316  static inline bool sign_gf_p(const g2_field_value_type &v) {
317  if (v.data[1] == 0) {
318  return sign_gf_p(v.data[0]);
319  }
320  return sign_gf_p(v.data[1]);
321  }
322 
323  template<typename GroupValueType, typename GroupAffineValueType>
324  static inline std::uint8_t evaluate_m_byte(const GroupValueType &point,
325  const GroupAffineValueType &point_affine,
326  bool compression) {
327  std::uint8_t result = 0;
328  if (compression) {
329  result |= C_bit;
330  }
331  // TODO: check condition of infinite point
332  if (point.is_zero()) {
333  result |= I_bit;
334  } else if (compression && sign_gf_p(point_affine.Y)) {
335  result |= S_bit;
336  }
337  return result;
338  }
339  };
340  } // namespace marshalling
341 } // namespace nil
342 
343 #endif // CRYPTO3_MARSHALLING_ALGEBRA_CURVES_HPP
A struct representing a BLS12-381 and BLS12-377 curve.
Definition: curves/bls12.hpp:49
Definition: pair.hpp:32
Definition: pair.hpp:31
g1_value_type::field_type::value_type g1_field_value_type
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:59
static g1_value_type compressed_to_g1_point(PointOctetsRange &point_octets, std::uint8_t m_byte)
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:196
static g1_value_type uncompressed_to_g1_point(PointOctetsRange &point_octets, std::uint8_t m_byte)
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:224
static bool sign_gf_p(const g1_field_value_type &v)
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:306
static g2_value_type compressed_to_g2_point(PointOctetsRange &point_octets, std::uint8_t m_byte)
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:245
std::array< std::uint8_t, 2 *sizeof_field_element > compressed_g2_octets
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:67
curve_type::template g1_type ::value_type g1_value_type
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:51
static g1_value_type octets_to_g1_point(const PointOctetsRange &octets)
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:150
g1_field_value_type::integral_type integral_type
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:62
algebra::curves::bls12_381 curve_type
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:49
curve_type::template g2_type< algebra::curves::coordinates::affine >::value_type g2_affine_value_type
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:57
curve_type::template g1_type< algebra::curves::coordinates::affine >::value_type g1_affine_value_type
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:55
std::array< std::uint8_t, 4 *sizeof_field_element > uncompressed_g2_octets
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:68
static g2_value_type octets_to_g2_point(const PointOctetsRange &octets)
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:170
std::array< std::uint8_t, sizeof_field_element > compressed_g1_octets
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:65
curve_type::template g2_type ::value_type g2_value_type
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:52
g2_value_type::field_type::value_type g2_field_value_type
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:60
static uncompressed_g2_octets point_to_octets(const g2_value_type &point)
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:119
static compressed_g2_octets point_to_octets_compress(const g2_value_type &point)
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:102
static std::uint8_t evaluate_m_byte(const GroupValueType &point, const GroupAffineValueType &point_affine, bool compression)
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:324
static uncompressed_g1_octets point_to_octets(const g1_value_type &point)
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:85
static bool sign_gf_p(const g2_field_value_type &v)
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:316
static compressed_g1_octets point_to_octets_compress(const g1_value_type &point)
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:72
static g2_value_type uncompressed_to_g2_point(PointOctetsRange &point_octets, std::uint8_t m_byte)
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:276
std::array< std::uint8_t, 2 *sizeof_field_element > uncompressed_g1_octets
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:66
Definition: algebra/include/nil/crypto3/algebra/curves/detail/marshalling.hpp:43