basic_operations.hpp
Go to the documentation of this file.
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2020-2021 Mikhail Komarov <nemo@nil.foundation>
3 // Copyright (c) 2020-2021 Nikita Kaskov <nbering@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_MATH_POLYNOMIAL_BASIC_OPERATIONS_HPP
27 #define CRYPTO3_MATH_POLYNOMIAL_BASIC_OPERATIONS_HPP
28 
29 #include <algorithm>
30 #include <vector>
31 
35 
36 namespace nil {
37  namespace crypto3 {
38  namespace math {
42  template<typename Range>
43  bool is_zero(const Range &a) {
44  return std::all_of(
45  std::begin(a),
46  std::end(a),
47  [](typename std::iterator_traits<decltype(std::begin(std::declval<Range>()))>::value_type i) {
48  return i ==
49  typename std::iterator_traits<decltype(std::begin(std::declval<Range>()))>::value_type();
50  });
51  }
52 
53  template<typename Range>
54  void reverse(Range &a, std::size_t n) {
55  std::reverse(std::begin(a), std::end(a));
56  a.resize(n);
57  }
58 
64  template<typename Range>
65  void condense(Range &a) {
66  while (std::distance(std::cbegin(a), std::cend(a)) > 1 &&
67  a.back() ==
68  typename std::iterator_traits<decltype(std::begin(std::declval<Range>()))>::value_type()) {
69  a.pop_back();
70  }
71  }
72 
77  template<typename Range>
78  void addition(Range &c, const Range &a, const Range &b) {
79 
80  typedef
81  typename std::iterator_traits<decltype(std::begin(std::declval<Range>()))>::value_type value_type;
82 
83  if (is_zero(a)) {
84  c = b;
85  } else if (is_zero(b)) {
86  c = a;
87  } else {
88  std::size_t a_size = std::distance(std::begin(a), std::end(a));
89  std::size_t b_size = std::distance(std::begin(b), std::end(b));
90 
91  if (a_size > b_size) {
92  c.resize(a_size);
94  std::begin(b), std::end(b), std::begin(a), std::begin(c), std::plus<value_type>());
95  std::copy(std::begin(a) + b_size, std::end(a), std::begin(c) + b_size);
96  } else {
97  c.resize(b_size);
99  std::begin(a), std::end(a), std::begin(b), std::begin(c), std::plus<value_type>());
100  std::copy(std::begin(b) + a_size, std::end(b), std::begin(c) + a_size);
101  }
102  }
103 
104  condense(c);
105  }
106 
111  template<typename Range>
112  void subtraction(Range &c, const Range &a, const Range &b) {
113 
114  typedef
115  typename std::iterator_traits<decltype(std::begin(std::declval<Range>()))>::value_type value_type;
116 
117  if (is_zero(b)) {
118  c = a;
119  } else if (is_zero(a)) {
120  c.resize(b.size());
121  std::transform(b.begin(), b.end(), c.begin(), std::negate<value_type>());
122  } else {
123  std::size_t a_size = a.size();
124  std::size_t b_size = b.size();
125 
126  if (a_size > b_size) {
127  c.resize(a_size);
128  std::transform(a.begin(), a.begin() + b_size, b.begin(), c.begin(), std::minus<value_type>());
129  std::copy(a.begin() + b_size, a.end(), c.begin() + b_size);
130  } else {
131  c.resize(b_size);
132  std::transform(a.begin(), a.end(), b.begin(), c.begin(), std::minus<value_type>());
133  std::transform(b.begin() + a_size, b.end(), c.begin() + a_size, std::negate<value_type>());
134  }
135  }
136 
137  condense(c);
138  }
139 
144  template<typename Range>
145  void fft_multiplication(Range &c, const Range &a, const Range &b) {
146 
147  typedef
148  typename std::iterator_traits<decltype(std::begin(std::declval<Range>()))>::value_type value_type;
149 
150  typedef typename value_type::field_type FieldType;
151  BOOST_STATIC_ASSERT(algebra::is_field<FieldType>::value);
152  BOOST_STATIC_ASSERT(std::is_same<typename FieldType::value_type, value_type>::value);
153 
154  const std::size_t n = detail::power_of_two(a.size() + b.size() - 1);
155  value_type omega = unity_root<FieldType>(n);
156 
157  Range u(a);
158  Range v(b);
159  u.resize(n, value_type::zero());
160  v.resize(n, value_type::zero());
161  c.resize(n, value_type::zero());
162 
163 #ifdef MULTICORE
164  detail::basic_parallel_radix2_fft<FieldType>(u, omega);
165  detail::basic_parallel_radix2_fft<FieldType>(v, omega);
166 #else
167  detail::basic_serial_radix2_fft<FieldType>(u, omega);
168  detail::basic_serial_radix2_fft<FieldType>(v, omega);
169 #endif
170 
171  std::transform(u.begin(), u.end(), v.begin(), c.begin(), std::multiplies<value_type>());
172 
173 #ifdef MULTICORE
174  detail::basic_parallel_radix2_fft<FieldType>(c, omega.inversed());
175 #else
176  detail::basic_serial_radix2_fft<FieldType>(c, omega.inversed());
177 #endif
178 
179  const value_type sconst = value_type(n).inversed();
180  std::transform(c.begin(),
181  c.end(),
182  c.begin(),
183  std::bind(std::multiplies<value_type>(), sconst, std::placeholders::_1));
184  condense(c);
185  }
186 
191  template<typename Range>
192  void multiplication(Range &c, const Range &a, const Range &b) {
193  fft_multiplication(c, a, b);
194  }
195 
201  template<typename Range>
202  Range transpose_multiplication(const std::size_t &n, const Range &a, const Range &c) {
203 
204  typedef
205  typename std::iterator_traits<decltype(std::begin(std::declval<Range>()))>::value_type value_type;
206 
207  const std::size_t m = a.size();
208  // if (c.size() - 1 > m + n)
209  // throw InvalidSizeException("expected c.size() - 1 <= m + n");
210 
211  Range r(a);
212  reverse(r, m);
213  multiplication(r, r, c);
214 
215  /* Determine Middle Product */
216  Range result;
217  for (std::size_t i = m - 1; i < n + m; i++) {
218  result.emplace_back(r[i]);
219  }
220  return result;
221  }
222 
228  template<typename Range>
229  void division(Range &q, Range &r, const Range &a, const Range &b) {
230 
231  typedef
232  typename std::iterator_traits<decltype(std::begin(std::declval<Range>()))>::value_type value_type;
233 
234  std::size_t d = b.size() - 1; /* Degree of B */
235  value_type c = b.back().inversed(); /* Inverse of Leading Coefficient of B */
236 
237  r = Range(a);
238  q = Range(r.size(), value_type::zero());
239 
240  std::size_t r_deg = r.size() - 1;
241  std::size_t shift;
242 
243  while (r_deg >= d && !is_zero(r)) {
244  if (r_deg >= d)
245  shift = r_deg - d;
246  else
247  shift = 0;
248 
249  value_type lead_coeff = r.back() * c;
250 
251  q[shift] += lead_coeff;
252 
253  if (b.size() + shift + 1 > r.size())
254  r.resize(b.size() + shift + 1);
255  auto glambda = [=](value_type x, value_type y) { return y - (x * lead_coeff); };
256  std::transform(b.begin(), b.end(), r.begin() + shift, r.begin() + shift, glambda);
257  condense(r);
258 
259  r_deg = r.size() - 1;
260  }
261  condense(q);
262  }
263  } // namespace math
264  } // namespace crypto3
265 } // namespace nil
266 
267 #endif // CRYPTO3_MATH_POLYNOMIAL_BASIC_OPERATIONS_HPP
decoded_range< UnaryFunction, SinglePassRange > transform(SinglePassRange &rng, UnaryFunction fn)
Definition: decrypted.hpp:100
constexpr std::size_t power_of_two(std::size_t n)
Definition: field_utils.hpp:51
void fft_multiplication(Range &c, const Range &a, const Range &b)
Definition: basic_operations.hpp:145
void addition(Range &c, const Range &a, const Range &b)
Definition: basic_operations.hpp:78
void multiplication(Range &c, const Range &a, const Range &b)
Definition: basic_operations.hpp:192
void condense(Range &a)
Definition: basic_operations.hpp:65
bool is_zero(const Range &a)
Definition: basic_operations.hpp:43
Range transpose_multiplication(const std::size_t &n, const Range &a, const Range &c)
Definition: basic_operations.hpp:202
void subtraction(Range &c, const Range &a, const Range &b)
Definition: basic_operations.hpp:112
void reverse(Range &a, std::size_t n)
Definition: basic_operations.hpp:54
void division(Range &q, Range &r, const Range &a, const Range &b)
Definition: basic_operations.hpp:229
Definition: pair.hpp:31
Definition: algebra/include/nil/crypto3/algebra/type_traits.hpp:95