|
@@ -230,6 +230,61 @@ 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
|
|
|
+// 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 FieldT P0x, P0y;
|
|
|
+ const pb_variable<FieldT> P1x, P1y;
|
|
|
+
|
|
|
+ ec_2_1constant_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> &which,
|
|
|
+ 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),
|
|
|
+ P0x(P0x), P0y(P0y), P1x(P1x), P1y(P1y)
|
|
|
+ {
|
|
|
+ // Allocate variables to protoboard
|
|
|
+
|
|
|
+ addx.allocate(this->pb, "addx");
|
|
|
+ addy.allocate(this->pb, "addy");
|
|
|
+ adder.emplace_back(this->pb, outx, outy, inx, iny, addx, addy);
|
|
|
+ }
|
|
|
+
|
|
|
+ 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));
|
|
|
+ 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;
|
|
|
+ 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
|
|
@@ -277,8 +332,9 @@ public:
|
|
|
|
|
|
void generate_r1cs_witness()
|
|
|
{
|
|
|
- this->pb.val(addx) = this->pb.val(which) ? this->pb.val(P1x) : this->pb.val(P0x);
|
|
|
- this->pb.val(addy) = this->pb.val(which) ? this->pb.val(P1y) : this->pb.val(P0y);
|
|
|
+ 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);
|
|
|
adder[0].generate_r1cs_witness();
|
|
|
}
|
|
|
};
|
|
@@ -619,7 +675,7 @@ class ec_scalarmul_vec_accum_gadget : public gadget<FieldT> {
|
|
|
private:
|
|
|
FieldT Cx, Cy;
|
|
|
pb_variable_array<FieldT> accumx, accumy;
|
|
|
- std::vector<ec_2_add_gadget<FieldT> > twoadders;
|
|
|
+ std::vector<ec_2_1constant_add_gadget<FieldT> > twoadders;
|
|
|
public:
|
|
|
const pb_variable<FieldT> outx, outy;
|
|
|
const pb_variable<FieldT> Ax, Ay;
|
|
@@ -798,7 +854,7 @@ class ec_scalarmul_gadget : public gadget<FieldT> {
|
|
|
private:
|
|
|
pb_variable_array<FieldT> svec;
|
|
|
std::vector<packing_gadget<FieldT> > packers;
|
|
|
- std::vector<ec_constant_scalarmul_vec_gadget<FieldT> > vecgadget;
|
|
|
+ std::vector<ec_scalarmul_vec_gadget<FieldT> > vecgadget;
|
|
|
|
|
|
public:
|
|
|
const pb_variable<FieldT> outx, outy;
|
|
@@ -833,6 +889,40 @@ public:
|
|
|
packers[0].generate_r1cs_witness_from_packed();
|
|
|
vecgadget[0].generate_r1cs_witness();
|
|
|
}
|
|
|
+
|
|
|
+ // Compute the addition table. The addition table is a variable array
|
|
|
+ // of length 2*numbits such that Ptable[2*i] and Ptable[2*i+1] are the
|
|
|
+ // (x,y) coordinates of 2^i * P + C.
|
|
|
+ static void compute_Ptable(protoboard<FieldT> &pb,
|
|
|
+ pb_variable_array<FieldT> &Ptable,
|
|
|
+ const FieldT &Px,
|
|
|
+ const FieldT &Py)
|
|
|
+ {
|
|
|
+ const FieldT Cx(2);
|
|
|
+ const FieldT Cy("4950745124018817972378217179409499695353526031437053848725554590521829916331");
|
|
|
+
|
|
|
+ assert(Ptable.size() % 2 == 0);
|
|
|
+ size_t numbits = Ptable.size() / 2;
|
|
|
+
|
|
|
+ FieldT twoiPx = Px;
|
|
|
+ FieldT twoiPy = Py;
|
|
|
+
|
|
|
+ for (size_t i = 0; i < numbits; ++i) {
|
|
|
+ // Invariant: (twoiPx, twoiPy) = 2^i * P
|
|
|
+
|
|
|
+ // Compute 2^i * P + C
|
|
|
+ FieldT twoiPCx, twoiPCy;
|
|
|
+ ec_add_points(twoiPCx, twoiPCy, twoiPx, twoiPy, Cx, Cy);
|
|
|
+ pb.val(Ptable[2*i]) = twoiPCx;
|
|
|
+ pb.val(Ptable[2*i+1]) = twoiPCy;
|
|
|
+
|
|
|
+ // Compute 2^{i+1} * P
|
|
|
+ FieldT twoi1Px, twoi1Py;
|
|
|
+ ec_double_point(twoi1Px, twoi1Py, twoiPx, twoiPy);
|
|
|
+ twoiPx = twoi1Px;
|
|
|
+ twoiPy = twoi1Py;
|
|
|
+ }
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
// Compute a*G + b*H as (outx, outy), given a and b as field elements.
|