Clearmatics Libff  0.1
C++ library for Finite Fields and Elliptic Curves
field_utils.tcc
Go to the documentation of this file.
1 /** @file
2  *****************************************************************************
3  Implementation of misc. math and serialization utility functions
4  *****************************************************************************
5  * @author This file is part of libff, developed by SCIPR Lab
6  * and contributors (see AUTHORS).
7  * @copyright MIT license (see LICENSE file)
8  *****************************************************************************/
9 
10 #ifndef FIELD_UTILS_TCC_
11 #define FIELD_UTILS_TCC_
12 
13 #include <complex>
14 #include <libff/algebra/fields/fp.hpp>
15 #include <libff/common/double.hpp>
16 #include <libff/common/utils.hpp>
17 #include <stdexcept>
18 
19 namespace libff
20 {
21 
22 namespace internal
23 {
24 
25 template<typename FieldT> class component_0_getter
26 {
27 public:
28  static const typename FieldT::my_Fp &get_component_0(const FieldT &field_el)
29  {
30  using NextSubfield =
31  typename std::decay<decltype(field_el.coeffs[0])>::type;
32  return component_0_getter<NextSubfield>::get_component_0(
33  field_el.coeffs[0]);
34  }
35 };
36 
37 template<mp_size_t n, const bigint<n> &modulus>
38 class component_0_getter<Fp_model<n, modulus>>
39 {
40 public:
41  static const Fp_model<n, modulus> &get_component_0(
42  const Fp_model<n, modulus> &field_el)
43  {
44  return field_el;
45  }
46 };
47 
48 } // namespace internal
49 
50 template<mp_size_t n>
51 size_t field_get_digit(
52  const bigint<n> &v, const size_t digit_size, const size_t digit_idx)
53 {
54  constexpr size_t limb_size_bits = 8 * sizeof(v.data[0]);
55  const size_t start_bit = digit_size * digit_idx;
56  const size_t end_bit = start_bit + digit_size;
57  const size_t low_limb = start_bit / limb_size_bits;
58  const size_t high_limb = end_bit / limb_size_bits;
59 
60  // low_limb < n <=> low_limb - n < 0
61  // <=> (low_limb - n) >> (limb_size_bits - 1) == 1
62  // use_low_limb == (low_limb - n) >> (limb_size_bits - 1)
63  //
64  const size_t use_low_limb = (low_limb - n) >> (limb_size_bits - 1);
65  assert(use_low_limb == (low_limb < n));
66 
67  const size_t low_limb_shift = start_bit - low_limb * limb_size_bits;
68 
69  // use_high_limb = (high_limb < n) && (high_limb != low_limb)
70  //
71  // high_limb < n <=> high_limb - n < 0
72  // <=> (high_limb - n) >> (limb_size_bits - 1) == 1
73  //
74  // high_limb != low_limb <=> high_limb - low_limb == 1
75  assert((high_limb == low_limb) || (high_limb == low_limb + 1));
76  const size_t use_high_limb =
77  ((high_limb - n) >> (limb_size_bits - 1)) & (high_limb - low_limb);
78  assert(use_high_limb == ((high_limb < n) && (high_limb != low_limb)));
79 
80  // if use_high_limb == 0, then high_limb_shift = c, which causes any high
81  // limb data to be shifted outside of the mask.
82  const size_t high_limb_bits =
83  use_high_limb * (end_bit - high_limb * limb_size_bits);
84  const size_t high_limb_shift = digit_size - high_limb_bits;
85 
86  const size_t mask = (1ull << digit_size) - 1;
87 
88  const size_t low_val = v.data[use_low_limb * low_limb];
89  const size_t low_val_shifted = low_val >> low_limb_shift;
90  const size_t low_val_final = use_low_limb * low_val_shifted;
91 
92  const size_t high_val = v.data[use_high_limb * high_limb];
93  const size_t high_val_shifted = high_val << high_limb_shift;
94  const size_t high_val_final = use_high_limb * high_val_shifted;
95 
96  const size_t value = mask & (low_val_final | high_val_final);
97 
98  assert((low_limb < n) || (value == 0));
99  return value;
100 }
101 
102 template<typename FieldT>
103 size_t field_get_num_signed_digits(const size_t digit_size)
104 {
105  // -1 in the field must have the largest number of 1's in the higher order
106  // elements of its binary representation.
107  const bigint<FieldT::num_limbs> minus_one = (-FieldT::one()).as_bigint();
108 
109  // The naive approach is to compute:
110  //
111  // ceil(FieldT::num_bits + 1 / digit_size)
112  //
113  // where the extra bit avoids the need to overflow in the final digit.
114  // However there are edges cases. Consider digit size 2 for a field where
115  // -1 has bits: 1 1 1 0 0 .... with 2-bit digit boundaries:
116  //
117  // 1 | 11 | 00
118  //
119  // The extra bit added in the calculation above becomes the SIGN bit of the
120  // high-order digit:
121  //
122  // 01 | 11 | 00
123  //
124  // and the second digit is guaranteed to overflow, in turn causing the 1st
125  // digit to overflow. We wish to minimize the number of digits used and
126  // rely on the naive calculation where possible. Therefore the actual value
127  // of the digits of -1 must be examined.
128 
129  // Examine the unsigned digits, checking for the case where the final digit
130  // overflows.
131 
132  const size_t naive_num_digits =
133  (FieldT::num_bits + 1 + digit_size - 1) / digit_size;
134  const size_t sign_bit_mask = 1ull << (digit_size - 1);
135  const size_t max_signed_value = sign_bit_mask - 1;
136 
137  // Check each unsigned digit, starting with the highest order. If it cannot
138  // overflow (< max_signed_value) then we can early-out and use
139  // naive_num_digits. If it will definitely overflow, we need an extra
140  // digit. If it is max_signed_value, move to the next least significant
141  // digit and repeat the check.
142 
143  bool final_overflow = false;
144  for (size_t i = naive_num_digits - 1; i < naive_num_digits; --i) {
145  const size_t unsigned_digit = field_get_digit(minus_one, digit_size, i);
146  if (unsigned_digit & sign_bit_mask) {
147  final_overflow = true;
148  break;
149  }
150 
151  if (unsigned_digit != max_signed_value) {
152  break;
153  }
154 
155  // This (and any previous values) are max_signed_value. Any lower-order
156  // digits which have the signed bit set will trigger an overflow up to
157  // the most-significant digit.
158  }
159 
160  if (final_overflow) {
161  return naive_num_digits + 1;
162  }
163 
164  return naive_num_digits;
165 }
166 
167 template<mp_size_t n>
168 ssize_t field_get_signed_digit(
169  const bigint<n> &v, const size_t digit_size, const size_t digit_index)
170 {
171  // digit x x x x
172  // carry_mask 1 0 0 0
173  // overflow_mask 1 0 0 0 0
174  const size_t carry_mask = 1ull << (digit_size - 1);
175  const size_t overflow_mask = 1ull << digit_size;
176  size_t carry = 0;
177  size_t overflow = 0;
178  size_t digit;
179  size_t i = 0;
180 
181  // For each digit:
182  // if overflow, then digit = 0, carry = 1
183  // if carry, digit = digit - overflow_mask,
184  // (because overflow_mask is also the value added when carrying into
185  // in the next digit)
186  // else digit = digit
187 
188  do {
189  // This is done at the start of the loop, rather than the end, since
190  // the individual values (before this OR) are required to compute the
191  // final value when this loop terminates.
192  carry = overflow | carry;
193 
194  const size_t raw_digit = field_get_digit(v, digit_size, i);
195  digit = raw_digit + carry;
196  overflow = (digit & overflow_mask) >> digit_size; // 1/0
197  carry = (digit & carry_mask) >> (digit_size - 1); // 1/0
198 
199  ++i;
200  } while (i <= digit_index);
201 
202  return (1 - overflow) * (digit - (carry * overflow_mask));
203 }
204 
205 template<typename FieldT>
206 void field_get_signed_digits(
207  std::vector<ssize_t> &digits,
208  const FieldT &v,
209  const size_t digit_size,
210  const size_t num_digits)
211 {
212  assert(digits.size() >= num_digits);
213 
214  // Code matches fixed_wnaf_digit(), but stores each digit.
215 
216  const size_t carry_mask = 1ull << (digit_size - 1);
217  const size_t overflow_mask = 1ll << digit_size;
218  const auto v_bi = v.as_bigint();
219 
220  size_t carry = 0;
221  size_t overflow = 0;
222 
223  for (size_t digit_idx = 0; digit_idx < num_digits; ++digit_idx) {
224  // if overflow, then digit = 0, carry = 1
225  // if carry, digit = digit - overflow_mask,
226  // (because overflow_mask is also the value added when carrying into
227  // in the next digit)
228  // else digit = digit
229 
230  carry = overflow | carry;
231  assert((carry == 0 || carry == 1));
232  const size_t raw_digit = field_get_digit(v_bi, digit_size, digit_idx);
233  const size_t digit = raw_digit + carry;
234  overflow = (digit & overflow_mask) >> digit_size; // 1/0
235  carry = (digit & carry_mask) >> (digit_size - 1); // 1/0
236 
237  digits[digit_idx] = (1 - overflow) * (digit - (carry * overflow_mask));
238  }
239 }
240 
241 template<typename FieldT> FieldT coset_shift()
242 {
243  return FieldT::multiplicative_generator.squared();
244 }
245 
246 template<typename FieldT>
247 typename std::enable_if<std::is_same<FieldT, Double>::value, bool>::type
248 has_root_of_unity(const size_t /*n*/)
249 {
250  return true;
251 }
252 
253 template<typename FieldT>
254 typename std::enable_if<!std::is_same<FieldT, Double>::value, bool>::type
255 has_root_of_unity(const size_t n)
256 {
257  const size_t logn = libff::log2(n);
258 
259  if (n != (1u << logn)) {
260  return false;
261  }
262 
263  if (logn > FieldT::s) {
264  return false;
265  }
266 
267  return true;
268 }
269 
270 template<typename FieldT>
271 typename std::enable_if<std::is_same<FieldT, Double>::value, FieldT>::type
272 get_root_of_unity(const size_t n)
273 {
274  const double PI = 3.141592653589793238460264338328L;
275 
276  return FieldT(cos(2 * PI / n), sin(2 * PI / n));
277 }
278 
279 template<typename FieldT>
280 typename std::enable_if<!std::is_same<FieldT, Double>::value, FieldT>::type
281 get_root_of_unity(const size_t n)
282 {
283  if (!has_root_of_unity<FieldT>(n)) {
284  throw std::invalid_argument("libff::get_root_of_unity: expected n == "
285  "(1u << logn) && logn <= FieldT::s");
286  }
287 
288  const size_t logn = log2(n);
289  FieldT omega = FieldT::root_of_unity;
290  for (size_t i = FieldT::s; i > logn; --i) {
291  omega *= omega;
292  }
293 
294  return omega;
295 }
296 
297 template<typename FieldT>
298 std::vector<FieldT> pack_int_vector_into_field_element_vector(
299  const std::vector<size_t> &v, const size_t w)
300 {
301  const size_t chunk_bits = FieldT::capacity();
302  const size_t repacked_size = div_ceil(v.size() * w, chunk_bits);
303  std::vector<FieldT> result(repacked_size);
304 
305  for (size_t i = 0; i < repacked_size; ++i) {
306  bigint<FieldT::num_limbs> b;
307  for (size_t j = 0; j < chunk_bits; ++j) {
308  const size_t word_index = (i * chunk_bits + j) / w;
309  const size_t pos_in_word = (i * chunk_bits + j) % w;
310  const size_t word_or_0 =
311  (word_index < v.size() ? v[word_index] : 0);
312  const size_t bit = (word_or_0 >> pos_in_word) & 1;
313 
314  b.data[j / GMP_NUMB_BITS] |= bit << (j % GMP_NUMB_BITS);
315  }
316  result[i] = FieldT(b);
317  }
318 
319  return result;
320 }
321 
322 template<typename FieldT>
323 std::vector<FieldT> pack_bit_vector_into_field_element_vector(
324  const bit_vector &v, const size_t chunk_bits)
325 {
326  assert(chunk_bits <= FieldT::capacity());
327 
328  const size_t repacked_size = div_ceil(v.size(), chunk_bits);
329  std::vector<FieldT> result(repacked_size);
330 
331  for (size_t i = 0; i < repacked_size; ++i) {
332  bigint<FieldT::num_limbs> b;
333  for (size_t j = 0; j < chunk_bits; ++j) {
334  b.data[j / GMP_NUMB_BITS] |=
335  ((i * chunk_bits + j) < v.size() && v[i * chunk_bits + j] ? 1ll
336  : 0ll)
337  << (j % GMP_NUMB_BITS);
338  }
339  result[i] = FieldT(b);
340  }
341 
342  return result;
343 }
344 
345 template<typename FieldT>
346 std::vector<FieldT> pack_bit_vector_into_field_element_vector(
347  const bit_vector &v)
348 {
349  return pack_bit_vector_into_field_element_vector<FieldT>(
350  v, FieldT::capacity());
351 }
352 
353 template<typename FieldT>
354 std::vector<FieldT> convert_bit_vector_to_field_element_vector(
355  const bit_vector &v)
356 {
357  std::vector<FieldT> result;
358  result.reserve(v.size());
359 
360  for (const bool b : v) {
361  result.emplace_back(b ? FieldT::one() : FieldT::zero());
362  }
363 
364  return result;
365 }
366 
367 template<typename FieldT>
368 bit_vector convert_field_element_vector_to_bit_vector(
369  const std::vector<FieldT> &v)
370 {
371  bit_vector result;
372 
373  for (const FieldT &el : v) {
374  const bit_vector el_bits =
375  convert_field_element_to_bit_vector<FieldT>(el);
376  result.insert(result.end(), el_bits.begin(), el_bits.end());
377  }
378 
379  return result;
380 }
381 
382 template<typename FieldT>
383 bit_vector convert_field_element_to_bit_vector(const FieldT &el)
384 {
385  bit_vector result;
386 
387  bigint<FieldT::num_limbs> b = el.as_bigint();
388  for (size_t i = 0; i < FieldT::size_in_bits(); ++i) {
389  result.push_back(b.test_bit(i));
390  }
391 
392  return result;
393 }
394 
395 template<typename FieldT>
396 bit_vector convert_field_element_to_bit_vector(
397  const FieldT &el, const size_t bitcount)
398 {
399  bit_vector result = convert_field_element_to_bit_vector(el);
400  result.resize(bitcount);
401 
402  return result;
403 }
404 
405 template<typename FieldT>
406 FieldT convert_bit_vector_to_field_element(const bit_vector &v)
407 {
408  assert(v.size() <= FieldT::size_in_bits());
409 
410  FieldT res = FieldT::zero();
411  FieldT c = FieldT::one();
412  for (bool b : v) {
413  res += b ? c : FieldT::zero();
414  c += c;
415  }
416  return res;
417 }
418 
419 template<typename FieldT> void batch_invert(std::vector<FieldT> &vec)
420 {
421  std::vector<FieldT> prod;
422  prod.reserve(vec.size());
423 
424  FieldT acc = FieldT::one();
425 
426  for (auto el : vec) {
427  assert(!el.is_zero());
428  prod.emplace_back(acc);
429  acc = acc * el;
430  }
431 
432  FieldT acc_inverse = acc.inverse();
433 
434  for (long i = static_cast<long>(vec.size() - 1); i >= 0; --i) {
435  const FieldT old_el = vec[i];
436  vec[i] = acc_inverse * prod[i];
437  acc_inverse = acc_inverse * old_el;
438  }
439 }
440 
441 template<typename FieldT>
442 const typename FieldT::my_Fp &field_get_component_0(const FieldT &v)
443 {
444  return internal::component_0_getter<FieldT>::get_component_0(v);
445 }
446 
447 template<
448  mp_size_t wn,
449  const bigint<wn> &wmodulus,
450  mp_size_t nn,
451  const bigint<nn> &nmodulus>
452 void fp_from_fp(Fp_model<wn, wmodulus> &wfp, const Fp_model<nn, nmodulus> &nfp)
453 {
454  bigint<wn> wint;
455  const bigint<nn> nint = nfp.as_bigint();
456  assert(wint.max_bits() >= nint.max_bits());
457  for (size_t limb_idx = 0; limb_idx < nn; ++limb_idx) {
458  wint.data[limb_idx] = nint.data[limb_idx];
459  }
460 
461  wfp = Fp_model<wn, wmodulus>(wint);
462 }
463 
464 template<typename FieldT> void print_vector(const std::vector<FieldT> &v)
465 {
466  for (size_t i = 0; i < v.size(); ++i) {
467  printf("[%2d]: ", (int)i);
468  v[i].print();
469  }
470 }
471 
472 } // namespace libff
473 
474 #endif // FIELD_UTILS_TCC_