arithmetic_sequence_domain.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_ARITHMETIC_SEQUENCE_DOMAIN_HPP
27 #define CRYPTO3_MATH_ARITHMETIC_SEQUENCE_DOMAIN_HPP
28 
29 #include <vector>
30 
32 
34 
35 #ifdef MULTICORE
36 #include <omp.h>
37 #endif
38 
39 namespace nil {
40  namespace crypto3 {
41  namespace math {
42 
43  using namespace nil::crypto3::algebra;
44 
45  template<typename FieldType>
46  class evaluation_domain;
47 
48  template<typename FieldType>
49  class arithmetic_sequence_domain : public evaluation_domain<FieldType> {
50  typedef typename FieldType::value_type value_type;
51 
52  public:
53  typedef FieldType field_type;
54 
56  std::vector<std::vector<std::vector<value_type>>> subproduct_tree;
57  std::vector<value_type> arithmetic_sequence;
59 
61  compute_subproduct_tree<FieldType>(this->subproduct_tree, log2(this->m));
62 
63  arithmetic_generator = value_type(fields::arithmetic_params<FieldType>::arithmetic_generator);
64 
65  arithmetic_sequence = std::vector<value_type>(this->m);
66  for (std::size_t i = 0; i < this->m; i++) {
67  arithmetic_sequence[i] = arithmetic_generator * value_type(i);
68  }
69 
70  precomputation_sentinel = true;
71  }
72 
73  arithmetic_sequence_domain(const std::size_t m) : evaluation_domain<FieldType>(m) {
74  if (m <= 1) {
75  throw std::invalid_argument("arithmetic(): expected m > 1");
76  }
77 
79  throw std::invalid_argument(
80  "arithmetic(): expected arithmetic_params<FieldType>::arithmetic_generator.is_zero() "
81  "!= true");
82  }
83 
84  precomputation_sentinel = false;
85  }
86 
87  void fft(std::vector<value_type> &a) {
88  if (a.size() != this->m) {
89  if (a.size() < this->m) {
90  a.resize(this->m, value_type(0));
91  } else {
92  throw std::invalid_argument("arithmetic: expected a.size() == this->m");
93  }
94  }
95 
96  if (!this->precomputation_sentinel) {
97  do_precomputation();
98  }
99 
100  /* Monomial to Newton */
101  monomial_to_newton_basis<FieldType>(a, subproduct_tree, this->m);
102 
103  /* Newton to Evaluation */
104  std::vector<value_type> S(this->m); /* i! * arithmetic_generator */
105  S[0] = value_type::one();
106 
107  value_type factorial = value_type::one();
108  for (std::size_t i = 1; i < this->m; i++) {
109  factorial *= value_type(i);
110  S[i] = (factorial * arithmetic_generator).inversed();
111  }
112 
113  multiplication(a, a, S);
114  a.resize(this->m);
115 
116 #ifdef MULTICORE
117 #pragma omp parallel for
118 #endif
119  for (std::size_t i = 0; i < this->m; i++) {
120  a[i] *= S[i].inversed();
121  }
122  }
123 
124  void inverse_fft(std::vector<value_type> &a) {
125  if (a.size() != this->m) {
126  if (a.size() < this->m) {
127  a.resize(this->m, value_type(0));
128  } else {
129  throw std::invalid_argument("arithmetic: expected a.size() == this->m");
130  }
131  }
132 
133  if (!this->precomputation_sentinel)
134  do_precomputation();
135 
136  /* Interpolation to Newton */
137  std::vector<value_type> S(this->m); /* i! * arithmetic_generator */
138  S[0] = value_type::one();
139 
140  std::vector<value_type> W(this->m);
141  W[0] = a[0] * S[0];
142 
143  value_type factorial = value_type::one();
144  for (std::size_t i = 1; i < this->m; i++) {
145  factorial *= value_type(i);
146  S[i] = (factorial * arithmetic_generator).inversed();
147  W[i] = a[i] * S[i];
148  if (i % 2 == 1)
149  S[i] = -S[i];
150  }
151 
152  multiplication(a, W, S);
153  a.resize(this->m);
154 
155  /* Newton to Monomial */
156  newton_to_monomial_basis<FieldType>(a, subproduct_tree, this->m);
157  }
158 
159  std::vector<value_type> evaluate_all_lagrange_polynomials(const value_type &t) {
160  /* Compute Lagrange polynomial of size m, with m+1 points (x_0, y_0), ... ,(x_m, y_m) */
161  /* Evaluate for x = t */
162  /* Return coeffs for each l_j(x) = (l / l_i[j]) * w[j] */
163 
164  if (!precomputation_sentinel)
165  do_precomputation();
166 
171  for (std::size_t i = 0; i < this->m; ++i) {
172  if (arithmetic_sequence[i] == t) // i.e., t equals this->arithmetic_sequence[i]
173  {
174  std::vector<value_type> res(this->m, value_type::zero());
175  res[i] = value_type::one();
176  return res;
177  }
178  }
179 
184  std::vector<value_type> l(this->m);
185  l[0] = t - this->arithmetic_sequence[0];
186 
187  value_type l_vanish = l[0];
188  value_type g_vanish = value_type::one();
189 
190  for (std::size_t i = 1; i < this->m; i++) {
191  l[i] = t - this->arithmetic_sequence[i];
192  l_vanish *= l[i];
193  g_vanish *= -this->arithmetic_sequence[i];
194  }
195 
196  std::vector<value_type> w(this->m);
197  w[0] = g_vanish.inversed() * (this->arithmetic_generator.pow(this->m - 1));
198 
199  l[0] = l_vanish * l[0].inversed() * w[0];
200  for (std::size_t i = 1; i < this->m; i++) {
201  value_type num = this->arithmetic_sequence[i - 1] - this->arithmetic_sequence[this->m - 1];
202  w[i] = w[i - 1] * num * this->arithmetic_sequence[i].inversed();
203  l[i] = l_vanish * l[i].inversed() * w[i];
204  }
205 
206  return l;
207  }
208  value_type get_domain_element(const std::size_t idx) {
209  if (!this->precomputation_sentinel)
210  do_precomputation();
211 
212  return this->arithmetic_sequence[idx];
213  }
214  value_type compute_vanishing_polynomial(const value_type &t) {
215  if (!this->precomputation_sentinel)
216  do_precomputation();
217 
218  /* Notes: Z = prod_{i = 0 to m} (t - a[i]) */
219  value_type Z = value_type::one();
220  for (std::size_t i = 0; i < this->m; i++) {
221  Z *= (t - this->arithmetic_sequence[i]);
222  }
223  return Z;
224  }
225  void add_poly_z(const value_type &coeff, std::vector<value_type> &H) {
226  if (H.size() != this->m + 1)
227  throw std::invalid_argument("arithmetic: expected H.size() == this->m+1");
228 
229  if (!this->precomputation_sentinel)
230  do_precomputation();
231 
232  std::vector<value_type> x(2, value_type::zero());
233  x[0] = -this->arithmetic_sequence[0];
234  x[1] = value_type::one();
235 
236  std::vector<value_type> t(2, value_type::zero());
237 
238  for (std::size_t i = 1; i < this->m + 1; i++) {
239  t[0] = -this->arithmetic_sequence[i];
240  t[1] = value_type::one();
241 
242  multiplication(x, x, t);
243  }
244 
245 #ifdef MULTICORE
246 #pragma omp parallel for
247 #endif
248  for (std::size_t i = 0; i < this->m + 1; i++) {
249  H[i] += (x[i] * coeff);
250  }
251  }
252  void divide_by_z_on_coset(std::vector<value_type> &P) {
253  const value_type coset = this->arithmetic_generator; /* coset in arithmetic sequence? */
254  const value_type Z_inverse_at_coset = this->compute_vanishing_polynomial(coset).inversed();
255  for (std::size_t i = 0; i < this->m; ++i) {
256  P[i] *= Z_inverse_at_coset;
257  }
258  }
259  };
260  } // namespace math
261  } // namespace crypto3
262 } // namespace nil
263 
264 #endif // ALGEBRA_FFT_ARITHMETIC_SEQUENCE_DOMAIN_HPP
Definition: arithmetic_sequence_domain.hpp:49
void do_precomputation()
Definition: arithmetic_sequence_domain.hpp:60
std::vector< value_type > evaluate_all_lagrange_polynomials(const value_type &t)
Definition: arithmetic_sequence_domain.hpp:159
std::vector< std::vector< std::vector< value_type > > > subproduct_tree
Definition: arithmetic_sequence_domain.hpp:56
FieldType field_type
Definition: arithmetic_sequence_domain.hpp:53
std::vector< value_type > arithmetic_sequence
Definition: arithmetic_sequence_domain.hpp:57
value_type get_domain_element(const std::size_t idx)
Definition: arithmetic_sequence_domain.hpp:208
bool precomputation_sentinel
Definition: arithmetic_sequence_domain.hpp:55
void add_poly_z(const value_type &coeff, std::vector< value_type > &H)
Definition: arithmetic_sequence_domain.hpp:225
value_type arithmetic_generator
Definition: arithmetic_sequence_domain.hpp:58
void inverse_fft(std::vector< value_type > &a)
Definition: arithmetic_sequence_domain.hpp:124
void divide_by_z_on_coset(std::vector< value_type > &P)
Definition: arithmetic_sequence_domain.hpp:252
arithmetic_sequence_domain(const std::size_t m)
Definition: arithmetic_sequence_domain.hpp:73
value_type compute_vanishing_polynomial(const value_type &t)
Definition: arithmetic_sequence_domain.hpp:214
void fft(std::vector< value_type > &a)
Definition: arithmetic_sequence_domain.hpp:87
Definition: evaluation_domain.hpp:41
Definition: pair.hpp:33
void multiplication(Range &c, const Range &a, const Range &b)
Definition: basic_operations.hpp:192
bool is_zero(const Range &a)
Definition: basic_operations.hpp:43
Definition: pair.hpp:31
Definition: fields/params.hpp:58