3939#include < nil/crypto3/algebra/fields/detail/element/fp2.hpp>
4040#include < nil/crypto3/algebra/fields/fp2.hpp>
4141
42+ #include < nil/blueprint/components/algebra/fields/plonk/non_native/detail/perform_fp2.hpp>
43+
4244namespace nil {
4345 namespace blueprint {
4446 namespace components {
45- namespace detail {
46- // actually compute bilinear forms that represent multiplication in F_p^2
47- template <typename T>
48- std::array<T,2 > perform_fp2_mult (std::array<T,2 > a, std::array<T,2 > b) {
49- std::array<T,2 > c = {a[0 ]*b[0 ] - a[1 ]*b[1 ], a[0 ]*b[1 ] + a[1 ]*b[0 ]};
50- return c;
51- }
52-
53- template <typename T>
54- std::array<T,2 > perform_fp2_add (std::array<T,2 > a, std::array<T,2 > b) {
55- std::array<T,2 > c = {a[0 ] + b[0 ], a[1 ] + b[1 ]};
56- return c;
57- }
58-
59- template <typename T>
60- std::array<T,2 > perform_fp2_sub (std::array<T,2 > a, std::array<T,2 > b) {
61- std::array<T,2 > c = {a[0 ] - b[0 ], a[1 ] - b[1 ]};
62- return c;
63- }
64-
65- template <typename T>
66- std::array<T,2 > perform_fp2_scale (std::array<T,2 > a, int x) {
67- std::array<T,2 > c = {a[0 ]*x, a[1 ]*x};
68- return c;
69- }
70- } // namespace detail
71- // E'(F_p^2) : y^2 = x^3 + 4(1+u) point doubling gate
47+ // E'(F_p^2) : y^2 = x^3 + 4(1+u) point doubling gate.
48+ // Expects point at infinity encoded by (0,0) in input and outputs (0,0) for its double
7249 // Input: (xP, yP) = P[4]
7350 // Output: (xR, yR) = R[4], R = [2]P as element of E'(F_p^2)
7451
@@ -107,7 +84,7 @@ namespace nil {
10784
10885 static manifest_type get_manifest () {
10986 static manifest_type manifest = manifest_type (
110- std::shared_ptr<manifest_param>(new manifest_single_value_param (8 )),
87+ std::shared_ptr<manifest_param>(new manifest_single_value_param (10 )),
11188 false
11289 );
11390 return manifest;
@@ -136,7 +113,7 @@ namespace nil {
136113
137114 result_type (const bls12_g2_point_double &component, std::uint32_t start_row_index) {
138115 for (std::size_t i = 0 ; i < 4 ; i++) {
139- R[i] = var (component.W (i+4 ), start_row_index, false , var::column_type::witness);
116+ R[i] = var (component.W (i+6 ), start_row_index, false , var::column_type::witness);
140117 }
141118 }
142119
@@ -190,21 +167,19 @@ namespace nil {
190167 fp2_element xP = fp2_element (var_value (assignment, instance_input.P [0 ]),
191168 var_value (assignment, instance_input.P [1 ])),
192169 yP = fp2_element (var_value (assignment, instance_input.P [2 ]),
193- var_value (assignment, instance_input.P [3 ]));
194- fp2_element xR, yR, lambda, nu;
195-
196- for (std::size_t i = 0 ; i < 4 ; i++) {
197- assignment.witness (component.W (i),start_row_index) = var_value (assignment, instance_input.P [i]);
198- }
199-
200- lambda = 3 *xP.pow (2 ) / (2 *yP);
201- nu = yP - lambda*xP;
202- xR = lambda.pow (2 ) - 2 *xP;
203- yR = -(lambda*xR + nu);
170+ var_value (assignment, instance_input.P [3 ])),
171+ lambda = 3 *xP.pow (2 ) / (2 *yP), // apparently division by 0 is defined as 0 to avoid exceptions
172+ nu = yP - lambda*xP,
173+ xR = lambda.pow (2 ) - 2 *xP,
174+ yR = -(lambda*xR + nu),
175+ zero_check = (xP * yP).inversed ();
204176
205177 for (std::size_t i = 0 ; i < 2 ; i++) {
206- assignment.witness (component.W (4 + i),start_row_index) = xR.data [i];
207- assignment.witness (component.W (6 + i),start_row_index) = yR.data [i];
178+ assignment.witness (component.W (i),start_row_index) = xP.data [i];
179+ assignment.witness (component.W (2 + i),start_row_index) = yP.data [i];
180+ assignment.witness (component.W (4 + i),start_row_index) = zero_check.data [i];
181+ assignment.witness (component.W (6 + i),start_row_index) = xR.data [i];
182+ assignment.witness (component.W (8 + i),start_row_index) = yR.data [i];
208183 }
209184
210185 return typename plonk_bls12_g2_point_double<BlueprintFieldType, ArithmetizationParams>::result_type (
@@ -223,20 +198,25 @@ namespace nil {
223198 using var = typename plonk_bls12_g2_point_double<BlueprintFieldType, ArithmetizationParams>::var;
224199 using constraint_type = crypto3::zk::snark::plonk_constraint<BlueprintFieldType>;
225200
226- std::array<constraint_type,2 > xP, yP, xR, yR, C1, C2;
201+ std::array<constraint_type,2 > xP, yP, ZC, xR, yR, C1, C2, C3, C4, C5 ;
227202
228203 for (std::size_t i = 0 ; i < 2 ; i++) {
229204 xP[i] = var (component.W (i), 0 , true );
230205 yP[i] = var (component.W (i+2 ), 0 , true );
231- xR[i] = var (component.W (i+4 ), 0 , true );
232- yR[i] = var (component.W (i+6 ), 0 , true );
206+ ZC[i] = var (component.W (i+4 ), 0 , true );
207+ xR[i] = var (component.W (i+6 ), 0 , true );
208+ yR[i] = var (component.W (i+8 ), 0 , true );
233209 }
234210 // the defining equations are
235211 // xR = (3xP^2 / 2yP)^2 - 2xP
236212 // yR = - (3xP^2 / 2yP) xR - yP + (3xP^2 / 2yP)xP
237213 // We transform them into constraints:
238214 // (2yP)^2 (xR + 2xP) - (3xP^2)^2 = 0
239215 // (2yP) (yR + yP) + (3xP^2)(xR - xP) = 0
216+ // Additional constraint to assure that the double of (0,0) is (0,0):
217+ // ZC * xP^2 * yP^2 - xP * yP = 0
218+ // ZC * xP * yP * xR - ZC * xP * yP = 0
219+ // ZC * xP * yP * yR - ZC * xP * yP = 0
240220
241221 C1 = perform_fp2_sub (
242222 perform_fp2_mult (
@@ -259,10 +239,21 @@ namespace nil {
259239 )
260240 );
261241
242+ C3 = perform_fp2_sub (
243+ perform_fp2_mult (ZC,perform_fp2_mult (perform_fp2_mult (xP,yP),perform_fp2_mult (xP,yP))),
244+ perform_fp2_mult (xP,yP)
245+ );
246+
247+ C4 = perform_fp2_sub ( xR, perform_fp2_mult (perform_fp2_mult (ZC,xR),perform_fp2_mult (xP,yP)));
248+ C5 = perform_fp2_sub ( yR, perform_fp2_mult (perform_fp2_mult (ZC,yR),perform_fp2_mult (xP,yP)));
249+
262250 std::vector<constraint_type> Cs = {};
263251 for (std::size_t i = 0 ; i < 2 ; i++) {
264252 Cs.push_back (C1[i]);
265253 Cs.push_back (C2[i]);
254+ Cs.push_back (C3[i]);
255+ Cs.push_back (C4[i]);
256+ Cs.push_back (C5[i]);
266257 }
267258 return bp.add_gate (Cs);
268259 }
0 commit comments