Skip to content
This repository was archived by the owner on Feb 17, 2025. It is now read-only.

Commit 90d2437

Browse files
committed
Doubling of point at infinity corrected
1 parent 6451ee8 commit 90d2437

File tree

3 files changed

+172
-64
lines changed

3 files changed

+172
-64
lines changed

include/nil/blueprint/components/algebra/curves/detail/plonk/bls12_g2_point_double.hpp

Lines changed: 36 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -39,36 +39,13 @@
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+
4244
namespace 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
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//---------------------------------------------------------------------------//
2+
// Copyright (c) 2023 Alexey Yashunsky <[email protected]>
3+
//
4+
// MIT License
5+
//
6+
// Permission is hereby granted, free of charge, to any person obtaining a copy
7+
// of this software and associated documentation files (the "Software"), to deal
8+
// in the Software without restriction, including without limitation the rights
9+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
// copies of the Software, and to permit persons to whom the Software is
11+
// furnished to do so, subject to the following conditions:
12+
//
13+
// The above copyright notice and this permission notice shall be included in all
14+
// copies or substantial portions of the Software.
15+
//
16+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
// SOFTWARE.
23+
//---------------------------------------------------------------------------//
24+
// @file Declaration of template functions for F_p^2 field operations.
25+
// with F_p^2 = F_p[u]/(u^2 - (-1)). They are intended for constraint generation.
26+
//---------------------------------------------------------------------------//
27+
28+
#ifndef CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_PERFORM_FP2_HPP
29+
#define CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_PERFORM_FP2_HPP
30+
31+
namespace nil {
32+
namespace blueprint {
33+
namespace components {
34+
namespace detail {
35+
// actually compute bilinear forms that represent multiplication in F_p^2
36+
template<typename T>
37+
std::array<T,2> perform_fp2_mult(std::array<T,2> a, std::array<T,2> b) {
38+
std::array<T,2> c = {a[0]*b[0] - a[1]*b[1], a[0]*b[1] + a[1]*b[0]};
39+
return c;
40+
}
41+
42+
template<typename T>
43+
std::array<T,2> perform_fp2_add(std::array<T,2> a, std::array<T,2> b) {
44+
std::array<T,2> c = {a[0] + b[0], a[1] + b[1]};
45+
return c;
46+
}
47+
48+
template<typename T>
49+
std::array<T,2> perform_fp2_sub(std::array<T,2> a, std::array<T,2> b) {
50+
std::array<T,2> c = {a[0] - b[0], a[1] - b[1]};
51+
return c;
52+
}
53+
54+
template<typename T>
55+
std::array<T,2> perform_fp2_scale(std::array<T,2> a, int x) {
56+
std::array<T,2> c = {a[0]*x, a[1]*x};
57+
return c;
58+
}
59+
} // namespace detail
60+
} // namespace components
61+
} // namespace blueprint
62+
} // namespace nil
63+
64+
#endif // CRYPTO3_BLUEPRINT_COMPONENTS_PLONK_PERFORM_FP2_HPP

test/algebra/curves/plonk/bls12_g2.cpp

Lines changed: 72 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ void test_bls12_g2_doubling(std::vector<typename CurveType::base_field_type::val
5151
using curve_type = CurveType;
5252
using BlueprintFieldType = typename curve_type::g2_type<>::field_type::base_field_type;
5353

54-
constexpr std::size_t WitnessColumns = 8;
54+
constexpr std::size_t WitnessColumns = 10;
5555
constexpr std::size_t PublicInputColumns = 1;
5656
constexpr std::size_t ConstantColumns = 0;
5757
constexpr std::size_t SelectorColumns = 1;
@@ -89,7 +89,7 @@ void test_bls12_g2_doubling(std::vector<typename CurveType::base_field_type::val
8989
assert(expected_y.data[1] == var_value(assignment, real_res.R[3]));
9090
};
9191

92-
component_type component_instance({0, 1, 2, 3, 4, 5, 6, 7},{},{});
92+
component_type component_instance({0, 1, 2, 3, 4, 5, 6, 7, 8, 9},{},{});
9393

9494
crypto3::test_component<component_type, BlueprintFieldType, ArithmetizationParams, hash_type, Lambda>(
9595
component_instance, public_input, result_check, instance_input);
@@ -108,23 +108,76 @@ BOOST_AUTO_TEST_CASE(blueprint_plonk_bls12_g2_test_381) {
108108
typedef typename group_type::field_type::value_type field_value_type;
109109
typedef typename group_type::field_type::integral_type integral_type;
110110

111-
group_value_type g2elem = group_value_type(field_value_type(integral_type("19354805336845174941142151562851080662656573665208680741935"
112-
"4395577367693778571452628423727082668900187036482254730"),
113-
integral_type("89193000964309942330810277795125089969455920364772498836102"
114-
"2851024990473423938537113948850338098230396747396259901")),
115-
field_value_type(integral_type("77171727205583415237828170597267125700535714547880090837365"
116-
"9404991537354153455452961747174765859335819766715637138"),
117-
integral_type("28103101185821266340411334541807053043930791391032529565024"
118-
"04531123692847658283858246402311867775854528543237781718")),
119-
field_value_type::one()),
120-
expected_res = g2elem * 2;
121-
122-
field_value_type g2x = g2elem.X / g2elem.Z.pow(2),
123-
g2y = g2elem.Y / g2elem.Z.pow(3);
124-
125-
std::vector<base_field_value> input = {g2x.data[0], g2x.data[1], g2y.data[0], g2y.data[1]};
126-
127-
test_bls12_g2_doubling<curve_type>(input, expected_res);
111+
std::vector<group_value_type> test_g2elems = { group_value_type(
112+
field_value_type(integral_type("19354805336845174941142151562851080662656573665208680741935"
113+
"4395577367693778571452628423727082668900187036482254730"),
114+
integral_type("89193000964309942330810277795125089969455920364772498836102"
115+
"2851024990473423938537113948850338098230396747396259901")),
116+
field_value_type(integral_type("77171727205583415237828170597267125700535714547880090837365"
117+
"9404991537354153455452961747174765859335819766715637138"),
118+
integral_type("28103101185821266340411334541807053043930791391032529565024"
119+
"04531123692847658283858246402311867775854528543237781718")),
120+
field_value_type::one()),
121+
group_value_type(
122+
field_value_type(integral_type("424958340463073975547762735517193206833255107941790909009827635"
123+
"556634414746056077714431786321247871628515967727334"),
124+
integral_type("301867980397012787726282639381447252855741350432919474049536385"
125+
"2840690589001358162447917674089074634504498585239512")),
126+
field_value_type(integral_type("362130818512839545988899552652712755661476860447213217606042330"
127+
"2734876099689739385100475320409412954617897892887112"),
128+
integral_type("102447784096837908713257069727879782642075240724579670654226801"
129+
"345708452018676587771714457671432122751958633012502")),
130+
field_value_type::one()),
131+
group_value_type(
132+
field_value_type(integral_type("278579072823914661770244330824853538101603574852069839969013232"
133+
"5213972292102741627498014391457605127656937478044880"),
134+
integral_type("385570939363183188091016781827643518714796337112619879965480309"
135+
"9743427431977934703201153169947378798970358200024876")),
136+
field_value_type(integral_type("821938378705205565995357931232097952117504537366318395539093959"
137+
"918654729488074273868834599496909844419980823111624"),
138+
integral_type("180242033557577995098293558042145430208756792638522270794752735"
139+
"3462942499437987207287862072369052390195154530059198")),
140+
field_value_type::one()),
141+
group_value_type(
142+
field_value_type(integral_type("394904109851368845549123118074972479469719294319673003085328501"
143+
"1755806989731870696216017360514887069032515603535834"),
144+
integral_type("141689369450613197680900293521221631713294194257076384932306538"
145+
"1335907430566747765697423320407614734575486820936593")),
146+
field_value_type(integral_type("322745371086383503299296260585144940139139935513544272889379018"
147+
"6263669279022343042444878900124369614767241382891922"),
148+
integral_type("149873883407375987188646612293399676447188951453282792720277792"
149+
"2460876335493588931070034160657995151627624577390178")),
150+
field_value_type::one()),
151+
group_value_type(
152+
field_value_type(integral_type("254155017921606149907129844368549510385368618440139550318910532"
153+
"874259603395336903946742408725761795820224536519988"),
154+
integral_type("276843145929673042677916621854414979160158598623313058301150172"
155+
"7704972362141149700714785450629498506208393873593705")),
156+
field_value_type(integral_type("175533934474433745731856511606202566998475061793772124522071142"
157+
"5551575490663761638802010265668157125441634554205566"),
158+
integral_type("560643043433789571968941329642646582974304556331567393300563909"
159+
"451776257854214387388500126524984624222885267024722")),
160+
field_value_type::one()),
161+
group_value_type(field_value_type::zero(), field_value_type::zero(),field_value_type::zero()) };
162+
163+
std::size_t i = 1;
164+
for( group_value_type & g2elem : test_g2elems ) {
165+
166+
std::cout << "Test instance # " << i << "\n";
167+
i++;
168+
169+
group_value_type expected_res = g2elem * 2;
170+
field_value_type g2x = field_value_type::zero(),
171+
g2y = field_value_type::zero(); // default is point at infinity, encoded as (0,0)
172+
173+
if (g2elem.Z != field_value_type::zero()) {
174+
g2x = g2elem.X / g2elem.Z.pow(2);
175+
g2y = g2elem.Y / g2elem.Z.pow(3);
176+
}
177+
std::vector<base_field_value> input = {g2x.data[0], g2x.data[1], g2y.data[0], g2y.data[1]};
178+
179+
test_bls12_g2_doubling<curve_type>(input, expected_res);
180+
}
128181
}
129182

130183
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)