element_fp3.hpp
Go to the documentation of this file.
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2018-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 // @file Declaration of interfaces for Fp3 components.
26 //
27 // The components verify field arithmetic in Fp3 = Fp[U]/(U^3-non_residue),
28 // where non_residue is in Fp.
29 //---------------------------------------------------------------------------//
30 
31 #ifndef CRYPTO3_ZK_BLUEPRINT_FP3_COMPONENTS_HPP
32 #define CRYPTO3_ZK_BLUEPRINT_FP3_COMPONENTS_HPP
33 
34 #include <memory>
35 
38 
40 
41 namespace nil {
42  namespace crypto3 {
43  namespace zk {
44  namespace components {
45 
46  /******************************** element_fp3 ************************************/
47 
51  template<typename Fp3T>
52  struct element_fp3 : public component<typename Fp3T::underlying_field_type> {
53 
54  using field_type = Fp3T;
55  using base_field_type = typename field_type::base_field_type;
56  using underlying_field_type = typename field_type::underlying_field_type;
57 
59 
60  using base_field_value_type = typename base_field_type::value_type;
61 
62  using data_type =
63  std::array<underlying_element_type, field_type::arity / underlying_field_type::arity>;
64 
66 
68 
70  blueprint_variable<base_field_type> c0_var, c1_var, c2_var;
71 
72  c0_var.allocate(bp);
73  c1_var.allocate(bp);
74  c2_var.allocate(bp);
75 
77  underlying_element_type(c2_var)});
78 
79  all_vars.emplace_back(data[0]);
80  all_vars.emplace_back(data[1]);
81  all_vars.emplace_back(data[2]);
82  }
83 
84  element_fp3(blueprint<base_field_type> &bp, const typename Fp3T::value_type &el) :
89 
90  c0_lc.assign(bp, el.data[0]);
91  c1_lc.assign(bp, el.data[1]);
92  c2_lc.assign(bp, el.data[2]);
93 
94  c0_lc.evaluate(bp);
95  c1_lc.evaluate(bp);
96  c2_lc.evaluate(bp);
97 
99  underlying_element_type(c2_lc)});
100 
101  all_vars.emplace_back(data[0]);
102  all_vars.emplace_back(data[1]);
103  all_vars.emplace_back(data[2]);
104  }
105 
107  const typename Fp3T::value_type &el,
110 
114 
115  c0_lc.assign(bp, el.data[0] * coeff);
116  c1_lc.assign(bp, el.data[1] * coeff);
117  c2_lc.assign(bp, el.data[2] * coeff);
118 
120  underlying_element_type(c2_lc)});
121 
122  all_vars.emplace_back(data[0]);
123  all_vars.emplace_back(data[1]);
124  all_vars.emplace_back(data[2]);
125  }
126 
128  const underlying_element_type &c0_lc,
129  const underlying_element_type &c1_lc,
130  const underlying_element_type &c2_lc) :
132 
134  underlying_element_type(c2_lc)});
135 
136  all_vars.emplace_back(data[0]);
137  all_vars.emplace_back(data[1]);
138  all_vars.emplace_back(data[2]);
139  }
140 
141  void generate_r1cs_equals_const_constraints(const typename Fp3T::value_type &el) {
142  this->bp.add_r1cs_constraint(snark::r1cs_constraint<base_field_type>(1, el.data[0], data[0]));
143  this->bp.add_r1cs_constraint(snark::r1cs_constraint<base_field_type>(1, el.data[1], data[1]));
144  this->bp.add_r1cs_constraint(snark::r1cs_constraint<base_field_type>(1, el.data[2], data[2]));
145  }
146 
147  void generate_r1cs_witness(const typename Fp3T::value_type &el) {
148  this->bp.lc_val(data[0]) = el.data[0];
149  this->bp.lc_val(data[1]) = el.data[1];
150  this->bp.lc_val(data[2]) = el.data[2];
151  }
152 
153  typename Fp3T::value_type get_element() {
154  typename Fp3T::value_type el;
155  el.data[0] = this->bp.lc_val(data[0]);
156  el.data[1] = this->bp.lc_val(data[1]);
157  el.data[2] = this->bp.lc_val(data[2]);
158  return el;
159  }
160 
161  element_fp3<Fp3T> operator*(const typename base_field_type::value_type &coeff) const {
162  underlying_element_type new_c0, new_c1, new_c2;
163  new_c0.assign(this->bp, this->data[0] * coeff);
164  new_c1.assign(this->bp, this->data[1] * coeff);
165  new_c2.assign(this->bp, this->data[2] * coeff);
166  return element_fp3<Fp3T>(this->bp, new_c0, new_c1, new_c2);
167  }
168 
170  underlying_element_type new_c0, new_c1, new_c2;
171  new_c0.assign(this->bp, this->data[0] + other.data[0]);
172  new_c1.assign(this->bp, this->data[1] + other.data[1]);
173  new_c2.assign(this->bp, this->data[2] + other.data[2]);
174  return element_fp3<Fp3T>(this->bp, new_c0, new_c1, new_c2);
175  }
176 
177  element_fp3<Fp3T> operator+(const typename Fp3T::value_type &other) const {
178  underlying_element_type new_c0, new_c1, new_c2;
179  new_c0.assign(this->bp, this->data[0] + other.data[0]);
180  new_c1.assign(this->bp, this->data[1] + other.data[1]);
181  new_c2.assign(this->bp, this->data[2] + other.data[2]);
182  return element_fp3<Fp3T>(this->bp, new_c0, new_c1, new_c2);
183  }
184 
186  underlying_element_type new_c0, new_c1, new_c2;
187  new_c0.assign(this->bp, this->data[2] * Fp3T::value_type::non_residue);
188 
189  new_c1.assign(this->bp, this->data[0]);
190  new_c2.assign(this->bp, this->data[1]);
191  return element_fp3<Fp3T>(this->bp, new_c0, new_c1, new_c2);
192  }
193 
194  void evaluate() const {
195  data[0].evaluate(this->bp);
196  data[1].evaluate(this->bp);
197  data[2].evaluate(this->bp);
198  }
199 
200  bool is_constant() const {
201  return (data[0].is_constant() && data[1].is_constant() && data[2].is_constant());
202  }
203 
204  static std::size_t size_in_bits() {
205  return 3 * base_field_type::value_bits;
206  }
207 
208  static std::size_t num_variables() {
209  return 3;
210  }
211  };
212 
213  /******************************** element_fp3_mul ************************************/
214 
218  template<typename Fp3T>
219  struct element_fp3_mul : public component<typename Fp3T::base_field_type> {
220  using base_field_type = typename Fp3T::base_field_type;
221 
225 
228 
230  const element_fp3<Fp3T> &A,
231  const element_fp3<Fp3T> &B,
232  const element_fp3<Fp3T> &result) :
234  A(A), B(B), result(result) {
235  v0.allocate(bp);
236  v4.allocate(bp);
237  }
238 
240  /*
241  Tom-Cook-3x for Fp3:
242  v0 = A.data[0] * B.data[0]
243  v1 = (A.data[0] + A.data[1] + A.data[2]) * (B.data[0] + B.data[1] + B.data[2])
244  v2 = (A.data[0] - A.data[1] + A.data[2]) * (B.data[0] - B.data[1] + B.data[2])
245  v3 = (A.data[0] + 2*A.data[1] + 4*A.data[2]) * (B.data[0] + 2*B.data[1] +
246  4*B.data[2]) v4 = A.data[2] * B.data[2] result.data[0] = v0 + non_residue * (v0/2 - v1/2
247  - v2/6 + v3/6 - 2*v4) result.data[1] = -(1/2) v0 + v1 - (1/3) v2 - (1/6) v3 + 2 v4 +
248  non_residue*v4 result.data[2] = -v0 + (1/2) v1 + (1/2) v2 - v4
249 
250  Enforced with 5 constraints. Doing so requires some care, as we first
251  compute two of the v_i explicitly, and then "inline" result.data[1]/data[2]/c3
252  in computations of teh remaining three v_i.
253 
254  Concretely, we first compute v0 and v4 explicitly, via 2 constraints:
255  A.data[0] * B.data[0] = v0
256  A.data[2] * B.data[2] = v4
257  Then we use the following 3 additional constraints:
258  v1 = result.data[1] + result.data[2] + (result.data[0] - v0)/non_residue + v0 + v4 -
259  non_residue v4 v2 = -result.data[1] + result.data[2] + v0 + (-result.data[0] +
260  v0)/non_residue + v4 + non_residue v4 v3 = 2 * result.data[1] + 4 result.data[2] +
261  (8*(result.data[0] - v0))/non_residue + v0 + 16 * v4 - 2 * non_residue * v4
262 
263  Reference:
264  "Multiplication and Squaring on Pairing-Friendly Fields"
265  Devegili, OhEigeartaigh, Scott, Dahab
266 
267  NOTE: the expressions above were cherry-picked from the Mathematica result
268  of the following command:
269 
270  (# -> Solve[{data[0] == v0 + non_residue*(v0/2 - v1/2 - v2/6 + v3/6 - 2 v4),
271  data[1] == -(1/2) v0 + v1 - (1/3) v2 - (1/6) v3 + 2 v4 + non_residue*v4,
272  data[2] == -v0 + (1/2) v1 + (1/2) v2 - v4}, #] // FullSimplify) & /@
273  Subsets[{v0, v1, v2, v3, v4}, {3}]
274  */
275  this->bp.add_r1cs_constraint(snark::r1cs_constraint<base_field_type>(A.data[0], B.data[0], v0));
276  this->bp.add_r1cs_constraint(snark::r1cs_constraint<base_field_type>(A.data[2], B.data[2], v4));
277 
278  const typename base_field_type::value_type beta = Fp3T::value_type::non_residue;
279 
280  this->bp.add_r1cs_constraint(snark::r1cs_constraint<base_field_type>(
281  A.data[0] + A.data[1] + A.data[2],
282  B.data[0] + B.data[1] + B.data[2],
283  result.data[1] + result.data[2] + result.data[0] * beta.inversed() +
284  v0 * (typename base_field_type::value_type(1) - beta.inversed()) +
285  v4 * (typename base_field_type::value_type(1) - beta)));
286  this->bp.add_r1cs_constraint(snark::r1cs_constraint<base_field_type>(
287  A.data[0] - A.data[1] + A.data[2],
288  B.data[0] - B.data[1] + B.data[2],
289  -result.data[1] + result.data[2] +
290  v0 * (typename base_field_type::value_type(1) + beta.inversed()) -
291  result.data[0] * beta.inversed() +
292  v4 * (typename base_field_type::value_type(1) + beta)));
293  this->bp.add_r1cs_constraint(snark::r1cs_constraint<base_field_type>(
294  A.data[0] + 2 * A.data[1] + 4 * A.data[2],
295  B.data[0] + 2 * B.data[1] + 4 * B.data[2],
296  2 * result.data[1] + 4 * result.data[2] +
297  result.data[0] * (typename base_field_type::value_type(8) * beta.inversed()) +
298  v0 * (typename base_field_type::value_type(1) -
299  typename base_field_type::value_type(8) * beta.inversed()) +
300  v4 * (typename base_field_type::value_type(16) -
301  typename base_field_type::value_type(2) * beta)));
302  }
303 
305  this->bp.val(v0) = this->bp.lc_val(A.data[0]) * this->bp.lc_val(B.data[0]);
306  this->bp.val(v4) = this->bp.lc_val(A.data[2]) * this->bp.lc_val(B.data[2]);
307 
308  const typename Fp3T::value_type Aval = A.get_element();
309  const typename Fp3T::value_type Bval = B.get_element();
310  const typename Fp3T::value_type Rval = Aval * Bval;
311  result.generate_r1cs_witness(Rval);
312  }
313  };
314 
315  /******************************** element_fp3_mul_by_lc ************************************/
316 
320  template<typename Fp3T>
321  struct element_fp3_mul_by_lc : public component<typename Fp3T::underlying_field_type> {
322  using base_field_type = typename Fp3T::underlying_field_type;
323 
327 
329  const element_fp3<Fp3T> &A,
331  const element_fp3<Fp3T> &result) :
333  A(A), lc(lc), result(result) {
334  }
335 
337  this->bp.add_r1cs_constraint(
339  this->bp.add_r1cs_constraint(
341  this->bp.add_r1cs_constraint(
343  }
344 
346  this->bp.lc_val(result.data[0]) = this->bp.lc_val(A.data[0]) * this->bp.lc_val(lc);
347  this->bp.lc_val(result.data[1]) = this->bp.lc_val(A.data[1]) * this->bp.lc_val(lc);
348  this->bp.lc_val(result.data[2]) = this->bp.lc_val(A.data[2]) * this->bp.lc_val(lc);
349  }
350  };
351 
352  /******************************** element_fp3_squared ************************************/
353 
357  template<typename Fp3T>
358  struct element_fp3_squared : public component<typename Fp3T::underlying_field_type> {
359  using base_field_type = typename Fp3T::underlying_field_type;
360 
363 
364  std::shared_ptr<element_fp3_mul<Fp3T>> mul;
365 
367  const element_fp3<Fp3T> &A,
368  const element_fp3<Fp3T> &result) :
370  A(A), result(result) {
371  mul.reset(new element_fp3_mul<Fp3T>(bp, A, A, result));
372  }
373 
375  mul->generate_r1cs_constraints();
376  }
377 
379  mul->generate_r1cs_witness();
380  }
381  };
382  } // namespace components
383  } // namespace zk
384  } // namespace crypto3
385 } // namespace nil
386 
387 #endif // CRYPTO3_ZK_BLUEPRINT_FP3_COMPONENTS_HPP
Definition: blueprint_linear_combination.hpp:47
void assign(blueprint< field_type > &bp, const snark::linear_combination< field_type > &lc)
Definition: blueprint_linear_combination.hpp:65
void evaluate(blueprint< field_type > &bp) const
Definition: blueprint_linear_combination.hpp:71
void allocate(blueprint< FieldType > &bp)
Definition: blueprint_variable.hpp:51
Definition: blueprint.hpp:46
Definition: component.hpp:37
blueprint< Fp3T::underlying_field_type > & bp
Definition: component.hpp:39
Definition: pair.hpp:31
typename Fp3T::underlying_field_type base_field_type
Definition: element_fp3.hpp:322
element_fp3_mul_by_lc(blueprint< base_field_type > &bp, const element_fp3< Fp3T > &A, const blueprint_linear_combination< base_field_type > &lc, const element_fp3< Fp3T > &result)
Definition: element_fp3.hpp:328
void generate_r1cs_constraints()
Definition: element_fp3.hpp:336
void generate_r1cs_witness()
Definition: element_fp3.hpp:345
element_fp3< Fp3T > A
Definition: element_fp3.hpp:324
element_fp3< Fp3T > result
Definition: element_fp3.hpp:326
blueprint_linear_combination< base_field_type > lc
Definition: element_fp3.hpp:325
Definition: element_fp3.hpp:219
element_fp3< Fp3T > A
Definition: element_fp3.hpp:222
blueprint_variable< base_field_type > v0
Definition: element_fp3.hpp:226
element_fp3_mul(blueprint< base_field_type > &bp, const element_fp3< Fp3T > &A, const element_fp3< Fp3T > &B, const element_fp3< Fp3T > &result)
Definition: element_fp3.hpp:229
typename Fp3T::base_field_type base_field_type
Definition: element_fp3.hpp:220
element_fp3< Fp3T > result
Definition: element_fp3.hpp:224
blueprint_variable< base_field_type > v4
Definition: element_fp3.hpp:227
void generate_r1cs_witness()
Definition: element_fp3.hpp:304
element_fp3< Fp3T > B
Definition: element_fp3.hpp:223
void generate_r1cs_constraints()
Definition: element_fp3.hpp:239
void generate_r1cs_witness()
Definition: element_fp3.hpp:378
typename Fp3T::underlying_field_type base_field_type
Definition: element_fp3.hpp:359
element_fp3< Fp3T > result
Definition: element_fp3.hpp:362
void generate_r1cs_constraints()
Definition: element_fp3.hpp:374
element_fp3_squared(blueprint< base_field_type > &bp, const element_fp3< Fp3T > &A, const element_fp3< Fp3T > &result)
Definition: element_fp3.hpp:366
element_fp3< Fp3T > A
Definition: element_fp3.hpp:361
std::shared_ptr< element_fp3_mul< Fp3T > > mul
Definition: element_fp3.hpp:364
Definition: element_fp3.hpp:52
element_fp3(blueprint< base_field_type > &bp, const typename Fp3T::value_type &el)
Definition: element_fp3.hpp:84
Fp3T::value_type get_element()
Definition: element_fp3.hpp:153
typename field_type::underlying_field_type underlying_field_type
Definition: element_fp3.hpp:56
typename base_field_type::value_type base_field_value_type
Definition: element_fp3.hpp:60
static std::size_t num_variables()
Definition: element_fp3.hpp:208
element_fp3(blueprint< base_field_type > &bp)
Definition: element_fp3.hpp:69
std::array< underlying_element_type, field_type::arity/underlying_field_type::arity > data_type
Definition: element_fp3.hpp:63
data_type data
Definition: element_fp3.hpp:65
static std::size_t size_in_bits()
Definition: element_fp3.hpp:204
element_fp3(blueprint< base_field_type > &bp, const typename Fp3T::value_type &el, const blueprint_linear_combination< base_field_type > &coeff)
Definition: element_fp3.hpp:106
element_fp3< Fp3T > mul_by_X() const
Definition: element_fp3.hpp:185
blueprint_linear_combination_vector< base_field_type > all_vars
Definition: element_fp3.hpp:67
void generate_r1cs_witness(const typename Fp3T::value_type &el)
Definition: element_fp3.hpp:147
element_fp3(blueprint< base_field_type > &bp, const underlying_element_type &c0_lc, const underlying_element_type &c1_lc, const underlying_element_type &c2_lc)
Definition: element_fp3.hpp:127
element_fp3< Fp3T > operator+(const typename Fp3T::value_type &other) const
Definition: element_fp3.hpp:177
bool is_constant() const
Definition: element_fp3.hpp:200
void evaluate() const
Definition: element_fp3.hpp:194
element_fp< underlying_field_type > underlying_element_type
Definition: element_fp3.hpp:58
Fp3T field_type
Definition: element_fp3.hpp:54
typename field_type::base_field_type base_field_type
Definition: element_fp3.hpp:55
element_fp3< Fp3T > operator+(const element_fp3< Fp3T > &other) const
Definition: element_fp3.hpp:169
element_fp3< Fp3T > operator*(const typename base_field_type::value_type &coeff) const
Definition: element_fp3.hpp:161
void generate_r1cs_equals_const_constraints(const typename Fp3T::value_type &el)
Definition: element_fp3.hpp:141