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 *****************************************************************************/
10 #ifndef FIELD_UTILS_TCC_
11 #define FIELD_UTILS_TCC_
14 #include <libff/algebra/fields/fp.hpp>
15 #include <libff/common/double.hpp>
16 #include <libff/common/utils.hpp>
25 template<typename FieldT> class component_0_getter
28 static const typename FieldT::my_Fp &get_component_0(const FieldT &field_el)
31 typename std::decay<decltype(field_el.coeffs[0])>::type;
32 return component_0_getter<NextSubfield>::get_component_0(
37 template<mp_size_t n, const bigint<n> &modulus>
38 class component_0_getter<Fp_model<n, modulus>>
41 static const Fp_model<n, modulus> &get_component_0(
42 const Fp_model<n, modulus> &field_el)
48 } // namespace internal
51 size_t field_get_digit(
52 const bigint<n> &v, const size_t digit_size, const size_t digit_idx)
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;
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)
64 const size_t use_low_limb = (low_limb - n) >> (limb_size_bits - 1);
65 assert(use_low_limb == (low_limb < n));
67 const size_t low_limb_shift = start_bit - low_limb * limb_size_bits;
69 // use_high_limb = (high_limb < n) && (high_limb != low_limb)
71 // high_limb < n <=> high_limb - n < 0
72 // <=> (high_limb - n) >> (limb_size_bits - 1) == 1
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)));
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;
86 const size_t mask = (1ull << digit_size) - 1;
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;
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;
96 const size_t value = mask & (low_val_final | high_val_final);
98 assert((low_limb < n) || (value == 0));
102 template<typename FieldT>
103 size_t field_get_num_signed_digits(const size_t digit_size)
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();
109 // The naive approach is to compute:
111 // ceil(FieldT::num_bits + 1 / digit_size)
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:
119 // The extra bit added in the calculation above becomes the SIGN bit of the
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.
129 // Examine the unsigned digits, checking for the case where the final digit
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;
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.
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;
151 if (unsigned_digit != max_signed_value) {
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.
160 if (final_overflow) {
161 return naive_num_digits + 1;
164 return naive_num_digits;
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)
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;
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
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;
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
200 } while (i <= digit_index);
202 return (1 - overflow) * (digit - (carry * overflow_mask));
205 template<typename FieldT>
206 void field_get_signed_digits(
207 std::vector<ssize_t> &digits,
209 const size_t digit_size,
210 const size_t num_digits)
212 assert(digits.size() >= num_digits);
214 // Code matches fixed_wnaf_digit(), but stores each digit.
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();
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
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
237 digits[digit_idx] = (1 - overflow) * (digit - (carry * overflow_mask));
241 template<typename FieldT> FieldT coset_shift()
243 return FieldT::multiplicative_generator.squared();
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*/)
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)
257 const size_t logn = libff::log2(n);
259 if (n != (1u << logn)) {
263 if (logn > FieldT::s) {
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)
274 const double PI = 3.141592653589793238460264338328L;
276 return FieldT(cos(2 * PI / n), sin(2 * PI / n));
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)
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");
288 const size_t logn = log2(n);
289 FieldT omega = FieldT::root_of_unity;
290 for (size_t i = FieldT::s; i > logn; --i) {
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)
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);
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;
314 b.data[j / GMP_NUMB_BITS] |= bit << (j % GMP_NUMB_BITS);
316 result[i] = FieldT(b);
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)
326 assert(chunk_bits <= FieldT::capacity());
328 const size_t repacked_size = div_ceil(v.size(), chunk_bits);
329 std::vector<FieldT> result(repacked_size);
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
337 << (j % GMP_NUMB_BITS);
339 result[i] = FieldT(b);
345 template<typename FieldT>
346 std::vector<FieldT> pack_bit_vector_into_field_element_vector(
349 return pack_bit_vector_into_field_element_vector<FieldT>(
350 v, FieldT::capacity());
353 template<typename FieldT>
354 std::vector<FieldT> convert_bit_vector_to_field_element_vector(
357 std::vector<FieldT> result;
358 result.reserve(v.size());
360 for (const bool b : v) {
361 result.emplace_back(b ? FieldT::one() : FieldT::zero());
367 template<typename FieldT>
368 bit_vector convert_field_element_vector_to_bit_vector(
369 const std::vector<FieldT> &v)
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());
382 template<typename FieldT>
383 bit_vector convert_field_element_to_bit_vector(const FieldT &el)
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));
395 template<typename FieldT>
396 bit_vector convert_field_element_to_bit_vector(
397 const FieldT &el, const size_t bitcount)
399 bit_vector result = convert_field_element_to_bit_vector(el);
400 result.resize(bitcount);
405 template<typename FieldT>
406 FieldT convert_bit_vector_to_field_element(const bit_vector &v)
408 assert(v.size() <= FieldT::size_in_bits());
410 FieldT res = FieldT::zero();
411 FieldT c = FieldT::one();
413 res += b ? c : FieldT::zero();
419 template<typename FieldT> void batch_invert(std::vector<FieldT> &vec)
421 std::vector<FieldT> prod;
422 prod.reserve(vec.size());
424 FieldT acc = FieldT::one();
426 for (auto el : vec) {
427 assert(!el.is_zero());
428 prod.emplace_back(acc);
432 FieldT acc_inverse = acc.inverse();
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;
441 template<typename FieldT>
442 const typename FieldT::my_Fp &field_get_component_0(const FieldT &v)
444 return internal::component_0_getter<FieldT>::get_component_0(v);
449 const bigint<wn> &wmodulus,
451 const bigint<nn> &nmodulus>
452 void fp_from_fp(Fp_model<wn, wmodulus> &wfp, const Fp_model<nn, nmodulus> &nfp)
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];
461 wfp = Fp_model<wn, wmodulus>(wint);
464 template<typename FieldT> void print_vector(const std::vector<FieldT> &v)
466 for (size_t i = 0; i < v.size(); ++i) {
467 printf("[%2d]: ", (int)i);
474 #endif // FIELD_UTILS_TCC_