element_fp2.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 Fp2 components.
26 //
27 // The components verify field arithmetic in Fp2 = Fp[U]/(U^2-non_residue),
28 // where non_residue is in Fp.
29 //---------------------------------------------------------------------------//
30 
31 #ifndef CRYPTO3_ZK_BLUEPRINT_FP2_COMPONENTS_HPP
32 #define CRYPTO3_ZK_BLUEPRINT_FP2_COMPONENTS_HPP
33 
34 #include <memory>
35 
38 
40 
41 namespace nil {
42  namespace crypto3 {
43  namespace zk {
44  namespace components {
45 
46  /******************************** element_fp2 ************************************/
47 
51  template<typename Fp2T>
52  struct element_fp2 : public component<typename Fp2T::underlying_field_type> {
53 
54  using field_type = Fp2T;
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 
71 
72  c0_var.allocate(bp);
73  c1_var.allocate(bp);
74 
75  // c0 = underlying_element_type(c0_var);
76  // c1 = underlying_element_type(c1_var);
77 
79 
80  all_vars.emplace_back(data[0]);
81  all_vars.emplace_back(data[1]);
82  }
83 
84  element_fp2(blueprint<base_field_type> &bp, const typename field_type::value_type &el) :
88 
89  c0_lc.assign(bp, el.data[0]);
90  c1_lc.assign(bp, el.data[1]);
91 
92  c0_lc.evaluate(bp);
93  c1_lc.evaluate(bp);
94 
96 
97  all_vars.emplace_back(data[0]);
98  all_vars.emplace_back(data[1]);
99  }
100 
102  const typename field_type::value_type &el,
105 
108 
109  c0_lc.assign(bp, el.data[0] * coeff);
110  c1_lc.assign(bp, el.data[1] * coeff);
111 
113 
114  all_vars.emplace_back(data[0]);
115  all_vars.emplace_back(data[1]);
116  }
117 
119  const underlying_element_type &c0_lc,
120  const underlying_element_type &c1_lc) :
122 
124 
125  all_vars.emplace_back(data[0]);
126  all_vars.emplace_back(data[1]);
127  }
128 
129  void generate_r1cs_equals_const_constraints(const typename Fp2T::value_type &el) {
130  this->bp.add_r1cs_constraint(snark::r1cs_constraint<base_field_type>(1, el.data[0], data[0]));
131  this->bp.add_r1cs_constraint(snark::r1cs_constraint<base_field_type>(1, el.data[1], data[1]));
132  }
133 
134  void generate_r1cs_witness(const typename Fp2T::value_type &el) {
135  this->bp.lc_val(data[0]) = el.data[0];
136  this->bp.lc_val(data[1]) = el.data[1];
137  }
138 
139  typename Fp2T::value_type get_element() {
140  typename Fp2T::value_type el;
141  el.data[0] = this->bp.lc_val(data[0]);
142  el.data[1] = this->bp.lc_val(data[1]);
143  return el;
144  }
145 
147  underlying_element_type new_c0, new_c1;
148  new_c0.assign(this->bp, this->data[0] * coeff);
149  new_c1.assign(this->bp, this->data[1] * coeff);
150  return element_fp2<Fp2T>(this->bp, new_c0, new_c1);
151  }
152 
153  element_fp2 operator+(const element_fp2 &other) const {
154  underlying_element_type new_c0, new_c1;
155  new_c0.assign(this->bp, this->data[0] + other.data[0]);
156  new_c1.assign(this->bp, this->data[1] + other.data[1]);
157  return element_fp2<Fp2T>(this->bp, new_c0, new_c1);
158  }
159 
160  element_fp2 operator+(const typename Fp2T::value_type &other) const {
161  underlying_element_type new_c0, new_c1;
162  new_c0.assign(this->bp, this->data[0] + other.data[0]);
163  new_c1.assign(this->bp, this->data[1] + other.data[1]);
164  return element_fp2<Fp2T>(this->bp, new_c0, new_c1);
165  }
166 
168  underlying_element_type new_c0, new_c1;
169  new_c0.assign(this->bp, this->data[1] * Fp2T::value_type::non_residue);
170 
171  new_c1.assign(this->bp, this->data[0]);
172  return element_fp2<Fp2T>(this->bp, new_c0, new_c1);
173  }
174 
175  void evaluate() const {
176  (this->data[0]).evaluate(this->bp);
177  (this->data[1]).evaluate(this->bp);
178  }
179 
180  bool is_constant() const {
181  return ((this->data[0]).is_constant() && (this->data[1]).is_constant());
182  }
183 
184  static std::size_t size_in_bits() {
185  return 2 * base_field_type::value_bits;
186  }
187 
188  static std::size_t num_variables() {
189  return 2;
190  }
191  };
192 
193  /******************************** element_fp2_mul ************************************/
194 
198  template<typename Fp2T>
199  struct element_fp2_mul : public component<typename Fp2T::underlying_field_type> {
200  using base_field_type = typename Fp2T::underlying_field_type;
201  using base_field_value_type = typename base_field_type::value_type;
202 
206 
207  private:
209 
210  public:
212  const element_fp2<Fp2T> &A,
213  const element_fp2<Fp2T> &B,
214  const element_fp2<Fp2T> &result) :
216  A(A), B(B), result(result) {
217  v1.allocate(bp);
218  }
219 
221  /*
222  Karatsuba multiplication for Fp2:
223  v0 = A.data[0] * B.data[0]
224  v1 = A.data[1] * B.data[1]
225  result.data[0] = v0 + non_residue * v1
226  result.data[1] = (A.data[0] + A.data[1]) * (B.data[0] + B.data[1]) - v0 - v1
227 
228  Enforced with 3 constraints:
229  A.data[1] * B.data[1] = v1
230  A.data[0] * B.data[0] = result.data[0] - non_residue * v1
231  (A.data[0]+A.data[1])*(B.data[0]+B.data[1]) = result.data[1] + result.data[0] + (1 -
232  non_residue) * v1
233 
234  Reference:
235  "Multiplication and Squaring on Pairing-Friendly Fields"
236  Devegili, OhEigeartaigh, Scott, Dahab
237  */
238  this->bp.add_r1cs_constraint(snark::r1cs_constraint<base_field_type>(A.data[1], B.data[1], v1));
239  this->bp.add_r1cs_constraint(snark::r1cs_constraint<base_field_type>(
240  A.data[0], B.data[0], result.data[0] + v1 * (-Fp2T::value_type::non_residue)));
241 
242  this->bp.add_r1cs_constraint(snark::r1cs_constraint<base_field_type>(
243  A.data[0] + A.data[1],
244  B.data[0] + B.data[1],
245  result.data[1] + result.data[0] +
246  v1 * (base_field_value_type::one() - Fp2T::value_type::non_residue)));
247  }
248 
250  const base_field_value_type aA = this->bp.lc_val(A.data[0]) * this->bp.lc_val(B.data[0]);
251  this->bp.val(v1) = this->bp.lc_val(A.data[1]) * this->bp.lc_val(B.data[1]);
252  this->bp.lc_val(result.data[0]) = aA + Fp2T::value_type::non_residue * this->bp.val(v1);
253 
254  this->bp.lc_val(result.data[1]) =
255  (this->bp.lc_val(A.data[0]) + this->bp.lc_val(A.data[1])) *
256  (this->bp.lc_val(B.data[0]) + this->bp.lc_val(B.data[1])) -
257  aA - this->bp.lc_val(v1);
258  }
259  };
260 
261  /******************************** element_fp2_mul_by_lc ************************************/
262 
266  template<typename Fp2T>
267  struct element_fp2_mul_by_lc : public component<typename Fp2T::underlying_field_type> {
268  using base_field_type = typename Fp2T::underlying_field_type;
269 
273 
275  const element_fp2<Fp2T> &A,
277  const element_fp2<Fp2T> &result) :
279  A(A), lc(lc), result(result) {
280  }
281 
283  this->bp.add_r1cs_constraint(
285  this->bp.add_r1cs_constraint(
287  }
288 
290  this->bp.lc_val(result.data[0]) = this->bp.lc_val(A.data[0]) * this->bp.lc_val(lc);
291  this->bp.lc_val(result.data[1]) = this->bp.lc_val(A.data[1]) * this->bp.lc_val(lc);
292  }
293  };
294 
295  /******************************** element_fp2_squared ************************************/
296 
300  template<typename Fp2T>
301  struct element_fp2_squared : public component<typename Fp2T::underlying_field_type> {
302  using base_field_type = typename Fp2T::base_field_type;
303 
306 
307  using base_field_value_type = typename base_field_type::value_type;
308 
310  const element_fp2<Fp2T> &A,
311  const element_fp2<Fp2T> &result) :
313  A(A), result(result) {
314  }
315 
317  /*
318  Complex multiplication for Fp2:
319  v0 = A.data[0] * A.data[1]
320  result.data[0] = (A.data[0] + A.data[1]) * (A.data[0] + non_residue * A.data[1]) -
321  (1 + non_residue) * v0 result.data[1] = 2 * v0
322 
323  Enforced with 2 constraints:
324  (2*A.data[0]) * A.data[1] = result.data[1]
325  (A.data[0] + A.data[1]) * (A.data[0] + non_residue * A.data[1]) = result.data[0] +
326  result.data[1] * (1 + non_residue)/2
327 
328  Reference:
329  "Multiplication and Squaring on Pairing-Friendly Fields"
330  Devegili, OhEigeartaigh, Scott, Dahab
331  */
332  this->bp.add_r1cs_constraint(
333  snark::r1cs_constraint<base_field_type>(2 * A.data[0], A.data[1], result.data[1]));
334  this->bp.add_r1cs_constraint(snark::r1cs_constraint<base_field_type>(
335  A.data[0] + A.data[1],
336  A.data[0] + Fp2T::value_type::non_residue * A.data[1],
337  result.data[0] + result.data[1] *
338  (base_field_value_type::one() + Fp2T::value_type::non_residue) *
339  base_field_value_type(0x02).inversed()));
340  }
341 
343  const base_field_value_type a = this->bp.lc_val(A.data[0]);
344  const base_field_value_type b = this->bp.lc_val(A.data[1]);
345  this->bp.lc_val(result.data[1]) = base_field_value_type(0x02) * a * b;
346  this->bp.lc_val(result.data[0]) = (a + b) * (a + Fp2T::value_type::non_residue * b) - a * b -
347  Fp2T::value_type::non_residue * a * b;
348  }
349  };
350  } // namespace components
351  } // namespace zk
352  } // namespace crypto3
353 } // namespace nil
354 
355 #endif // CRYPTO3_ZK_BLUEPRINT_FP2_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< Fp2T::underlying_field_type > & bp
Definition: component.hpp:39
Definition: pair.hpp:31
void generate_r1cs_constraints()
Definition: element_fp2.hpp:282
void generate_r1cs_witness()
Definition: element_fp2.hpp:289
element_fp2_mul_by_lc(blueprint< base_field_type > &bp, const element_fp2< Fp2T > &A, const blueprint_linear_combination< base_field_type > &lc, const element_fp2< Fp2T > &result)
Definition: element_fp2.hpp:274
element_fp2< Fp2T > A
Definition: element_fp2.hpp:270
blueprint_linear_combination< base_field_type > lc
Definition: element_fp2.hpp:271
element_fp2< Fp2T > result
Definition: element_fp2.hpp:272
typename Fp2T::underlying_field_type base_field_type
Definition: element_fp2.hpp:268
Definition: element_fp2.hpp:199
element_fp2< Fp2T > A
Definition: element_fp2.hpp:203
typename Fp2T::underlying_field_type base_field_type
Definition: element_fp2.hpp:200
typename base_field_type::value_type base_field_value_type
Definition: element_fp2.hpp:201
element_fp2< Fp2T > result
Definition: element_fp2.hpp:205
void generate_r1cs_witness()
Definition: element_fp2.hpp:249
element_fp2_mul(blueprint< base_field_type > &bp, const element_fp2< Fp2T > &A, const element_fp2< Fp2T > &B, const element_fp2< Fp2T > &result)
Definition: element_fp2.hpp:211
void generate_r1cs_constraints()
Definition: element_fp2.hpp:220
element_fp2< Fp2T > B
Definition: element_fp2.hpp:204
void generate_r1cs_constraints()
Definition: element_fp2.hpp:316
typename base_field_type::value_type base_field_value_type
Definition: element_fp2.hpp:307
void generate_r1cs_witness()
Definition: element_fp2.hpp:342
element_fp2< Fp2T > result
Definition: element_fp2.hpp:305
element_fp2_squared(blueprint< base_field_type > &bp, const element_fp2< Fp2T > &A, const element_fp2< Fp2T > &result)
Definition: element_fp2.hpp:309
element_fp2< Fp2T > A
Definition: element_fp2.hpp:304
typename Fp2T::base_field_type base_field_type
Definition: element_fp2.hpp:302
Definition: element_fp2.hpp:52
element_fp< underlying_field_type > underlying_element_type
Definition: element_fp2.hpp:58
element_fp2(blueprint< base_field_type > &bp)
Definition: element_fp2.hpp:69
typename base_field_type::value_type base_field_value_type
Definition: element_fp2.hpp:60
void evaluate() const
Definition: element_fp2.hpp:175
blueprint_linear_combination_vector< base_field_type > all_vars
Definition: element_fp2.hpp:67
static std::size_t size_in_bits()
Definition: element_fp2.hpp:184
element_fp2 mul_by_X() const
Definition: element_fp2.hpp:167
data_type data
Definition: element_fp2.hpp:65
bool is_constant() const
Definition: element_fp2.hpp:180
element_fp2 operator*(const base_field_value_type &coeff) const
Definition: element_fp2.hpp:146
static std::size_t num_variables()
Definition: element_fp2.hpp:188
Fp2T::value_type get_element()
Definition: element_fp2.hpp:139
element_fp2 operator+(const typename Fp2T::value_type &other) const
Definition: element_fp2.hpp:160
typename field_type::base_field_type base_field_type
Definition: element_fp2.hpp:55
Fp2T field_type
Definition: element_fp2.hpp:54
element_fp2 operator+(const element_fp2 &other) const
Definition: element_fp2.hpp:153
element_fp2(blueprint< base_field_type > &bp, const typename field_type::value_type &el)
Definition: element_fp2.hpp:84
typename field_type::underlying_field_type underlying_field_type
Definition: element_fp2.hpp:56
element_fp2(blueprint< base_field_type > &bp, const typename field_type::value_type &el, const blueprint_linear_combination< base_field_type > &coeff)
Definition: element_fp2.hpp:101
void generate_r1cs_equals_const_constraints(const typename Fp2T::value_type &el)
Definition: element_fp2.hpp:129
std::array< underlying_element_type, field_type::arity/underlying_field_type::arity > data_type
Definition: element_fp2.hpp:63
element_fp2(blueprint< base_field_type > &bp, const underlying_element_type &c0_lc, const underlying_element_type &c1_lc)
Definition: element_fp2.hpp:118
void generate_r1cs_witness(const typename Fp2T::value_type &el)
Definition: element_fp2.hpp:134