|
@@ -184,18 +184,17 @@ public:
|
|
|
|
|
|
// Add the constant EC point P0 or the constant EC point P1 to the
|
|
|
// variable EC point (inx,iny) to yield (outx,outy). The input point
|
|
|
-// must not be the point at infinity. The input bit which controls
|
|
|
+// must not be the point at infinity. The input bit choice controls
|
|
|
// which addition is done.
|
|
|
template<typename FieldT>
|
|
|
class ec_2_constant_add_gadget : public gadget<FieldT> {
|
|
|
private:
|
|
|
- pb_variable<FieldT> sumx, sumy;
|
|
|
pb_linear_combination<FieldT> addx, addy;
|
|
|
std::vector<ec_add_gadget<FieldT> > adder;
|
|
|
public:
|
|
|
const pb_variable<FieldT> outx, outy;
|
|
|
const pb_linear_combination<FieldT> inx, iny;
|
|
|
- const pb_variable<FieldT> which;
|
|
|
+ const pb_variable<FieldT> choice;
|
|
|
const FieldT P0x, P0y, P1x, P1y;
|
|
|
|
|
|
ec_2_constant_add_gadget(protoboard<FieldT> &pb,
|
|
@@ -203,17 +202,17 @@ public:
|
|
|
const pb_variable<FieldT> &outy,
|
|
|
const pb_linear_combination<FieldT> &inx,
|
|
|
const pb_linear_combination<FieldT> &iny,
|
|
|
- const pb_variable<FieldT> &which,
|
|
|
+ const pb_variable<FieldT> &choice,
|
|
|
const FieldT &P0x, const FieldT &P0y,
|
|
|
const FieldT &P1x, const FieldT &P1y) :
|
|
|
gadget<FieldT>(pb, "ec_2_constant_add_gadget"),
|
|
|
- outx(outx), outy(outy), inx(inx), iny(iny), which(which),
|
|
|
+ outx(outx), outy(outy), inx(inx), iny(iny), choice(choice),
|
|
|
P0x(P0x), P0y(P0y), P1x(P1x), P1y(P1y)
|
|
|
{
|
|
|
// Allocate variables to protoboard
|
|
|
|
|
|
- addx.assign(pb, which * (P1x-P0x) + P0x);
|
|
|
- addy.assign(pb, which * (P1y-P0y) + P0y);
|
|
|
+ addx.assign(pb, choice * (P1x-P0x) + P0x);
|
|
|
+ addy.assign(pb, choice * (P1y-P0y) + P0y);
|
|
|
adder.emplace_back(this->pb, outx, outy, inx, iny, addx, addy);
|
|
|
}
|
|
|
|
|
@@ -232,18 +231,17 @@ public:
|
|
|
|
|
|
// Add the constant EC point P0 or the variable EC point P1 to the
|
|
|
// variable EC point (inx,iny) to yield (outx,outy). The input point
|
|
|
-// must not be the point at infinity. The input bit which controls
|
|
|
+// must not be the point at infinity. The input bit choice controls
|
|
|
// which addition is done.
|
|
|
template<typename FieldT>
|
|
|
class ec_2_1constant_add_gadget : public gadget<FieldT> {
|
|
|
private:
|
|
|
- pb_variable<FieldT> sumx, sumy;
|
|
|
pb_variable<FieldT> addx, addy;
|
|
|
std::vector<ec_add_gadget<FieldT> > adder;
|
|
|
public:
|
|
|
const pb_variable<FieldT> outx, outy;
|
|
|
const pb_linear_combination<FieldT> inx, iny;
|
|
|
- const pb_variable<FieldT> which;
|
|
|
+ const pb_variable<FieldT> choice;
|
|
|
const FieldT P0x, P0y;
|
|
|
const pb_variable<FieldT> P1x, P1y;
|
|
|
|
|
@@ -252,13 +250,13 @@ public:
|
|
|
const pb_variable<FieldT> &outy,
|
|
|
const pb_linear_combination<FieldT> &inx,
|
|
|
const pb_linear_combination<FieldT> &iny,
|
|
|
- const pb_variable<FieldT> &which,
|
|
|
+ const pb_variable<FieldT> &choice,
|
|
|
const FieldT &P0x,
|
|
|
const FieldT &P0y,
|
|
|
const pb_variable<FieldT> &P1x,
|
|
|
const pb_variable<FieldT> &P1y) :
|
|
|
gadget<FieldT>(pb, "ec_2_1constant_add_gadget"),
|
|
|
- outx(outx), outy(outy), inx(inx), iny(iny), which(which),
|
|
|
+ outx(outx), outy(outy), inx(inx), iny(iny), choice(choice),
|
|
|
P0x(P0x), P0y(P0y), P1x(P1x), P1y(P1y)
|
|
|
{
|
|
|
// Allocate variables to protoboard
|
|
@@ -270,35 +268,34 @@ public:
|
|
|
|
|
|
void generate_r1cs_constraints()
|
|
|
{
|
|
|
- // Set (addx,addy) = which ? (P0x, P0y) : (P1x, P1y)
|
|
|
- this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(P1x - P0x, which, addx - P0x));
|
|
|
- this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(P1y - P0y, which, addy - P0y));
|
|
|
+ // Set (addx,addy) = choice ? (P0x, P0y) : (P1x, P1y)
|
|
|
+ this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(P1x - P0x, choice, addx - P0x));
|
|
|
+ this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(P1y - P0y, choice, addy - P0y));
|
|
|
adder[0].generate_r1cs_constraints();
|
|
|
}
|
|
|
|
|
|
void generate_r1cs_witness()
|
|
|
{
|
|
|
- bool whichb = this->pb.val(which) != FieldT(0);
|
|
|
- this->pb.val(addx) = whichb ? this->pb.val(P1x) : P0x;
|
|
|
- this->pb.val(addy) = whichb ? this->pb.val(P1y) : P0y;
|
|
|
+ bool choiceb = this->pb.val(choice) != FieldT(0);
|
|
|
+ this->pb.val(addx) = choiceb ? this->pb.val(P1x) : P0x;
|
|
|
+ this->pb.val(addy) = choiceb ? this->pb.val(P1y) : P0y;
|
|
|
adder[0].generate_r1cs_witness();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// Add the variable EC point P0 or the variable EC point P1 to the
|
|
|
// variable EC point (inx,iny) to yield (outx,outy). The input point
|
|
|
-// must not be the point at infinity. The input bit which controls
|
|
|
+// must not be the point at infinity. The input bit choice controls
|
|
|
// which addition is done.
|
|
|
template<typename FieldT>
|
|
|
class ec_2_add_gadget : public gadget<FieldT> {
|
|
|
private:
|
|
|
- pb_variable<FieldT> sumx, sumy;
|
|
|
pb_variable<FieldT> addx, addy;
|
|
|
std::vector<ec_add_gadget<FieldT> > adder;
|
|
|
public:
|
|
|
const pb_variable<FieldT> outx, outy;
|
|
|
const pb_linear_combination<FieldT> inx, iny;
|
|
|
- const pb_variable<FieldT> which;
|
|
|
+ const pb_variable<FieldT> choice;
|
|
|
const pb_variable<FieldT> P0x, P0y, P1x, P1y;
|
|
|
|
|
|
ec_2_add_gadget(protoboard<FieldT> &pb,
|
|
@@ -306,13 +303,13 @@ public:
|
|
|
const pb_variable<FieldT> &outy,
|
|
|
const pb_linear_combination<FieldT> &inx,
|
|
|
const pb_linear_combination<FieldT> &iny,
|
|
|
- const pb_variable<FieldT> &which,
|
|
|
+ const pb_variable<FieldT> &choice,
|
|
|
const pb_variable<FieldT> &P0x,
|
|
|
const pb_variable<FieldT> &P0y,
|
|
|
const pb_variable<FieldT> &P1x,
|
|
|
const pb_variable<FieldT> &P1y) :
|
|
|
gadget<FieldT>(pb, "ec_2_add_gadget"),
|
|
|
- outx(outx), outy(outy), inx(inx), iny(iny), which(which),
|
|
|
+ outx(outx), outy(outy), inx(inx), iny(iny), choice(choice),
|
|
|
P0x(P0x), P0y(P0y), P1x(P1x), P1y(P1y)
|
|
|
{
|
|
|
// Allocate variables to protoboard
|
|
@@ -324,110 +321,78 @@ public:
|
|
|
|
|
|
void generate_r1cs_constraints()
|
|
|
{
|
|
|
- // Set (addx,addy) = which ? (P0x, P0y) : (P1x, P1y)
|
|
|
- this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(P1x - P0x, which, addx - P0x));
|
|
|
- this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(P1y - P0y, which, addy - P0y));
|
|
|
+ // Set (addx,addy) = choice ? (P0x, P0y) : (P1x, P1y)
|
|
|
+ this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(P1x - P0x, choice, addx - P0x));
|
|
|
+ this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(P1y - P0y, choice, addy - P0y));
|
|
|
adder[0].generate_r1cs_constraints();
|
|
|
}
|
|
|
|
|
|
void generate_r1cs_witness()
|
|
|
{
|
|
|
- bool whichb = this->pb.val(which) != FieldT(0);
|
|
|
- this->pb.val(addx) = whichb ? this->pb.val(P1x) : this->pb.val(P0x);
|
|
|
- this->pb.val(addy) = whichb ? this->pb.val(P1y) : this->pb.val(P0y);
|
|
|
+ bool choiceb = this->pb.val(choice) != FieldT(0);
|
|
|
+ this->pb.val(addx) = choiceb ? this->pb.val(P1x) : this->pb.val(P0x);
|
|
|
+ this->pb.val(addy) = choiceb ? this->pb.val(P1y) : this->pb.val(P0y);
|
|
|
adder[0].generate_r1cs_witness();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-#if 0
|
|
|
-// Add nothing, or one of the constant EC points P1, P2, or P3 to the EC
|
|
|
-// point (inx,iny) to yield (outx,outy). The input point must not be
|
|
|
-// the point at infinity. The two input bits add1 and add2 control what
|
|
|
-// is added. Typically, P3 will equal P1+P2, in which case this gadget
|
|
|
-// does two conditional constant adds simultaneously in just 6 constraints.
|
|
|
+// Add one of the four constant EC points to the variable EC point
|
|
|
+// (inx,iny) to yield (outx,outy). The input point must not be the
|
|
|
+// point at infinity. The input bits choice0 and choice1 control which
|
|
|
+// addition is done (P{2*choice1+choice0} is added).
|
|
|
template<typename FieldT>
|
|
|
-class ec_add_P123_gadget : public gadget<FieldT> {
|
|
|
+class ec_4_constant_add_gadget : public gadget<FieldT> {
|
|
|
private:
|
|
|
- pb_variable<FieldT> lambda, sumx, sumy, move;
|
|
|
+ pb_variable<FieldT> both;
|
|
|
+ pb_linear_combination<FieldT> addx, addy;
|
|
|
+ std::vector<ec_add_gadget<FieldT> > adder;
|
|
|
public:
|
|
|
const pb_variable<FieldT> outx, outy;
|
|
|
const pb_linear_combination<FieldT> inx, iny;
|
|
|
- const pb_variable<FieldT> add1, add2;
|
|
|
- const FieldT P1x, P1y, P2x, P2y, P3x, P3y;
|
|
|
+ const pb_variable<FieldT> choice0, choice1;
|
|
|
+ const FieldT P0x, P0y, P1x, P1y, P2x, P2y, P3x, P3y;
|
|
|
|
|
|
- ec_add_P123_gadget(protoboard<FieldT> &pb,
|
|
|
+ ec_4_constant_add_gadget(protoboard<FieldT> &pb,
|
|
|
const pb_variable<FieldT> &outx,
|
|
|
const pb_variable<FieldT> &outy,
|
|
|
const pb_linear_combination<FieldT> &inx,
|
|
|
const pb_linear_combination<FieldT> &iny,
|
|
|
- const pb_variable<FieldT> &add1,
|
|
|
- const pb_variable<FieldT> &add2,
|
|
|
+ const pb_variable<FieldT> &choice0,
|
|
|
+ const pb_variable<FieldT> &choice1,
|
|
|
+ const FieldT &P0x, const FieldT &P0y,
|
|
|
const FieldT &P1x, const FieldT &P1y,
|
|
|
const FieldT &P2x, const FieldT &P2y,
|
|
|
- const FieldT &P3x, const FieldT &P3y) :
|
|
|
- gadget<FieldT>(pb, "ec_add_P123_gadget"),
|
|
|
- outx(outx), outy(outy), inx(inx), iny(iny), add1(add1), add2(add2),
|
|
|
- P1x(P1x), P1y(P1y), P2x(P2x), P2y(P2y), P3x(P3x), P3y(P3y)
|
|
|
+ const FieldT &P3x, const FieldT &P3y) :
|
|
|
+ gadget<FieldT>(pb, "ec_4_constant_add_gadget"),
|
|
|
+ outx(outx), outy(outy), inx(inx), iny(iny),
|
|
|
+ choice0(choice0), choice1(choice1),
|
|
|
+ P0x(P0x), P0y(P0y), P1x(P1x), P1y(P1y),
|
|
|
+ P2x(P2x), P2y(P2y), P3x(P3x), P3y(P3y)
|
|
|
{
|
|
|
// Allocate variables to protoboard
|
|
|
- // The strings (like "x") are only for debugging purposes
|
|
|
|
|
|
- lambda.allocate(this->pb, "lambda");
|
|
|
- sumx.allocate(this->pb, "sumx");
|
|
|
- sumy.allocate(this->pb, "sumy");
|
|
|
- move.allocate(this->pb, "move");
|
|
|
+ both.allocate(this->pb, "both");
|
|
|
+ addx.assign(this->pb, both * (P3x - P2x - P1x + P0x) + choice1 * (P2x - P0x) + choice0 * (P1x - P0x) + P0x);
|
|
|
+ addy.assign(this->pb, both * (P3y - P2y - P1y + P0y) + choice1 * (P2y - P0y) + choice0 * (P1y - P0y) + P0y);
|
|
|
+ adder.emplace_back(this->pb, outx, outy, inx, iny, addx, addy);
|
|
|
}
|
|
|
|
|
|
void generate_r1cs_constraints()
|
|
|
{
|
|
|
- // Strategy: if add1 = add2 = 0, we compute some nonsense but throw
|
|
|
- // it away later. Otherwise, the coordinates of the point to add
|
|
|
- // are a _linear_ function of add1 and add2 (since P1, P2, and P3
|
|
|
- // are public constants)
|
|
|
-
|
|
|
- // In particular, the point to add is ( (P3x - P2x) * add1 + (P3x -
|
|
|
- // P1x) * add2 + (P1x + P2x - P3x), (P3y - P2y) * add1 + (P3y - P1y) *
|
|
|
- // add2 + (P1y + P2y - P3y))
|
|
|
-
|
|
|
- // (addx - inx) * lambda = addy - iny
|
|
|
- this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>((P3x - P2x) * add1 + (P3x - P1x) * add2 + (P1x + P2x - P3x) - inx, lambda, (P3y - P2y) * add1 + (P3y - P1y) * add2 + (P1y + P2y - P3y) - iny));
|
|
|
-
|
|
|
- // sumx = lambda^2 - (addx + inx)
|
|
|
- this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(lambda, lambda, sumx + (P3x - P2x) * add1 + (P3x - P1x) * add2 + (P1x + P2x - P3x) + inx));
|
|
|
-
|
|
|
- // sumy = lambda * (inx - sumx) - iny
|
|
|
- this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(lambda, inx - sumx, sumy + iny));
|
|
|
-
|
|
|
- // Now we want to conditionally move the sum. We want that
|
|
|
- // outx = (add1 || add2) ? sumx : inx
|
|
|
- // outy = (add1 || add2) ? sumy : iny
|
|
|
-
|
|
|
- // so we compute move = add1 || add2, and then
|
|
|
- // outx = inx + (sumx - inx) * move
|
|
|
- // outy = iny + (sumy - iny) * move
|
|
|
-
|
|
|
- this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(1 - add1, 1 - add2, 1 - move));
|
|
|
- this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(sumx - inx, move, outx - inx));
|
|
|
- this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(sumy - iny, move, outy - iny));
|
|
|
-
|
|
|
+ this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(choice0, choice1, both));
|
|
|
+ adder[0].generate_r1cs_constraints();
|
|
|
}
|
|
|
|
|
|
void generate_r1cs_witness()
|
|
|
{
|
|
|
- FieldT addxval = (P3x - P2x) * this->pb.val(add1) + (P3x - P1x) * this->pb.val(add2) + (P1x + P2x - P3x);
|
|
|
- FieldT addyval = (P3y - P2y) * this->pb.val(add1) + (P3y - P1y) * this->pb.val(add2) + (P1y + P2y - P3y);
|
|
|
- this->pb.val(lambda) = (addyval - this->pb.lc_val(iny)) * (addxval - this->pb.lc_val(inx)).inverse();
|
|
|
- this->pb.val(sumx) = this->pb.val(lambda).squared() - (addxval + this->pb.lc_val(inx));
|
|
|
- this->pb.val(sumy) = this->pb.val(lambda) * (this->pb.lc_val(inx) - this->pb.val(sumx)) - this->pb.lc_val(iny);
|
|
|
-
|
|
|
- bool a1 = this->pb.val(add1) != FieldT(0);
|
|
|
- bool a2 = this->pb.val(add2) != FieldT(0);
|
|
|
- this->pb.val(move) = a1 || a2;
|
|
|
- this->pb.val(outx) = (a1 || a2) ? this->pb.val(sumx) : this->pb.lc_val(inx);
|
|
|
- this->pb.val(outy) = (a1 || a2) ? this->pb.val(sumy) : this->pb.lc_val(iny);
|
|
|
+ bool c0 = this->pb.val(choice0) != FieldT(0);
|
|
|
+ bool c1 = this->pb.val(choice1) != FieldT(0);
|
|
|
+ this->pb.val(both) = c0 && c1;
|
|
|
+ addx.evaluate(this->pb);
|
|
|
+ addy.evaluate(this->pb);
|
|
|
+ adder[0].generate_r1cs_witness();
|
|
|
}
|
|
|
};
|
|
|
-#endif
|
|
|
|
|
|
// Compute A + s*P as (outx, outy) for an accumulator A, a given
|
|
|
// constant point P, and s given as a bit vector. The _caller_ is
|
|
@@ -440,6 +405,7 @@ class ec_constant_scalarmul_vec_accum_gadget : public gadget<FieldT> {
|
|
|
private:
|
|
|
FieldT Cx, Cy;
|
|
|
pb_variable_array<FieldT> accumx, accumy;
|
|
|
+ std::vector<ec_4_constant_add_gadget<FieldT> > fouradders;
|
|
|
std::vector<ec_2_constant_add_gadget<FieldT> > twoadders;
|
|
|
public:
|
|
|
const pb_variable<FieldT> outx, outy;
|
|
@@ -467,29 +433,69 @@ public:
|
|
|
outx(outx), outy(outy), Ax(Ax), Ay(Ay), svec(svec), Px(Px), Py(Py)
|
|
|
{
|
|
|
size_t numbits = svec.size();
|
|
|
- accumx.allocate(this->pb, numbits-1, "accumx");
|
|
|
- accumy.allocate(this->pb, numbits-1, "accumy");
|
|
|
+ // See loop comments below: if numbits is odd, we need (numbits-1)/2
|
|
|
+ // slots. If numbits is even, we need (numbits-2)/2 slots. So
|
|
|
+ // with integer truncated division, (numbits-1)/2 will be correct
|
|
|
+ // in both cases. (Well, if numbits is 0 for some reason, we also want
|
|
|
+ // to get 0.)
|
|
|
+ size_t accumslots = 0;
|
|
|
+ if (numbits > 0) {
|
|
|
+ accumslots = (numbits-1)/2;
|
|
|
+ }
|
|
|
+ accumx.allocate(this->pb, accumslots, "accumx");
|
|
|
+ accumy.allocate(this->pb, accumslots, "accumy");
|
|
|
|
|
|
FieldT twoiPx = Px, twoiPy = Py;
|
|
|
- size_t i = 0;
|
|
|
+ size_t i = 0, accnext = 0;
|
|
|
|
|
|
while(i < numbits) {
|
|
|
// Invariant: twoiP = 2^i * P
|
|
|
- FieldT twoiPCx, twoiPCy;
|
|
|
- ec_add_points(twoiPCx, twoiPCy, twoiPx, twoiPy, Cx, Cy);
|
|
|
-
|
|
|
- twoadders.emplace_back(this->pb,
|
|
|
- (i == numbits-1 ? outx : accumx[i]),
|
|
|
- (i == numbits-1 ? outy : accumy[i]),
|
|
|
- (i == 0 ? Ax : accumx[i-1]),
|
|
|
- (i == 0 ? Ay : accumy[i-1]),
|
|
|
- svec[i], Cx, Cy, twoiPCx, twoiPCy);
|
|
|
+ // Invariant: i is even and accnext = i/2
|
|
|
+
|
|
|
+ if (i == numbits-1) {
|
|
|
+ FieldT twoiPCx, twoiPCy;
|
|
|
+ ec_add_points(twoiPCx, twoiPCy, twoiPx, twoiPy, Cx, Cy);
|
|
|
+
|
|
|
+ twoadders.emplace_back(this->pb,
|
|
|
+ outx, outy,
|
|
|
+ (i == 0 ? Ax : accumx[accnext-1]),
|
|
|
+ (i == 0 ? Ay : accumy[accnext-1]),
|
|
|
+ svec[i], Cx, Cy, twoiPCx, twoiPCy);
|
|
|
+
|
|
|
+ // This makes i odd, but also exits the loop with
|
|
|
+ // i = numbits and accnext = (numbits-1)/2
|
|
|
+ i += 1;
|
|
|
+ } else {
|
|
|
+ // Do two bits at a time
|
|
|
+
|
|
|
+ // We need to compute 2^i * a * P + C for a = 1,2,3
|
|
|
+ FieldT twoi2Px, twoi2Py;
|
|
|
+ FieldT twoi1PCx, twoi1PCy, twoi2PCx, twoi2PCy, twoi3PCx, twoi3PCy;
|
|
|
+
|
|
|
+ ec_add_points(twoi1PCx, twoi1PCy, twoiPx, twoiPy, Cx, Cy);
|
|
|
+ ec_double_point(twoi2Px, twoi2Py, twoiPx, twoiPy);
|
|
|
+ ec_add_points(twoi2PCx, twoi2PCy, twoi2Px, twoi2Py, Cx, Cy);
|
|
|
+ ec_add_points(twoi3PCx, twoi3PCy, twoi2Px, twoi2Py,
|
|
|
+ twoi1PCx, twoi1PCy);
|
|
|
+
|
|
|
+ fouradders.emplace_back(this->pb,
|
|
|
+ (i == numbits-2 ? outx : accumx[accnext]),
|
|
|
+ (i == numbits-2 ? outy : accumy[accnext]),
|
|
|
+ (i == 0 ? Ax : accumx[accnext-1]),
|
|
|
+ (i == 0 ? Ay : accumy[accnext-1]),
|
|
|
+ svec[i], svec[i+1], Cx, Cy, twoi1PCx, twoi1PCy,
|
|
|
+ twoi2PCx, twoi2PCy, twoi3PCx, twoi3PCy);
|
|
|
+
|
|
|
+ // If i == numbits-2, we write directly to out and not accum above, and
|
|
|
+ // exit the loop with i even and i == numbits and accnext = (numbits-2)/2
|
|
|
+ if (i < numbits - 2) {
|
|
|
+ accnext += 1;
|
|
|
+ }
|
|
|
+ i += 2;
|
|
|
+ ec_double_point(twoiPx, twoiPy, twoi2Px, twoi2Py);
|
|
|
+ }
|
|
|
|
|
|
- FieldT newtwoiPx, newtwoiPy, newAXSx, newAXSy;
|
|
|
- ec_double_point(newtwoiPx, newtwoiPy, twoiPx, twoiPy);
|
|
|
- twoiPx = newtwoiPx;
|
|
|
- twoiPy = newtwoiPy;
|
|
|
- i += 1;
|
|
|
+ FieldT newAXSx, newAXSy;
|
|
|
ec_add_points(newAXSx, newAXSy, AXSx, AXSy, Cx, Cy);
|
|
|
AXSx = newAXSx;
|
|
|
AXSy = newAXSy;
|
|
@@ -498,6 +504,9 @@ public:
|
|
|
|
|
|
void generate_r1cs_constraints()
|
|
|
{
|
|
|
+ for (auto&& gadget : fouradders) {
|
|
|
+ gadget.generate_r1cs_constraints();
|
|
|
+ }
|
|
|
for (auto&& gadget : twoadders) {
|
|
|
gadget.generate_r1cs_constraints();
|
|
|
}
|
|
@@ -505,6 +514,9 @@ public:
|
|
|
|
|
|
void generate_r1cs_witness()
|
|
|
{
|
|
|
+ for (auto&& gadget : fouradders) {
|
|
|
+ gadget.generate_r1cs_witness();
|
|
|
+ }
|
|
|
for (auto&& gadget : twoadders) {
|
|
|
gadget.generate_r1cs_witness();
|
|
|
}
|