|
@@ -182,10 +182,10 @@ public:
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-// Add 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 which addition
|
|
|
-// is done.
|
|
|
+// 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
|
|
|
+// which addition is done.
|
|
|
template<typename FieldT>
|
|
|
class ec_2_constant_add_gadget : public gadget<FieldT> {
|
|
|
private:
|
|
@@ -230,6 +230,59 @@ public:
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+// 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
|
|
|
+// 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> P0x, P0y, P1x, P1y;
|
|
|
+
|
|
|
+ ec_2_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 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),
|
|
|
+ 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()
|
|
|
+ {
|
|
|
+ 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);
|
|
|
+ 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
|
|
@@ -552,6 +605,236 @@ public:
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+// Compute A + s*P as (outx, outy) for an accumulator A, a precomputed
|
|
|
+// addition table Ptable for a variable point P, and s given as a bit
|
|
|
+// vector. The _caller_ is responsible for proving that the elements of
|
|
|
+// svec are bits. The (constant) accumulator excess (AXS) will be
|
|
|
+// updated; when all the computations are complete, AXS should be
|
|
|
+// subtracted from the accumulator A. The addition table is a variable
|
|
|
+// array of length 2*numbits (where numbits is the length of svec) such
|
|
|
+// that Ptable[2*i] and Ptable[2*i+1] are the (x,y) coordinates of
|
|
|
+// 2^i * P + C.
|
|
|
+template<typename FieldT>
|
|
|
+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;
|
|
|
+public:
|
|
|
+ const pb_variable<FieldT> outx, outy;
|
|
|
+ const pb_variable<FieldT> Ax, Ay;
|
|
|
+ const pb_variable_array<FieldT> svec, Ptable;
|
|
|
+
|
|
|
+ ec_scalarmul_vec_accum_gadget(protoboard<FieldT> &pb,
|
|
|
+ const pb_variable<FieldT> &outx,
|
|
|
+ const pb_variable<FieldT> &outy,
|
|
|
+ const pb_variable<FieldT> &Ax,
|
|
|
+ const pb_variable<FieldT> &Ay,
|
|
|
+ const pb_variable_array<FieldT> &svec,
|
|
|
+ const pb_variable_array<FieldT> &Ptable,
|
|
|
+ FieldT &AXSx, FieldT &AXSy) :
|
|
|
+ gadget<FieldT>(pb, "ec_scalarmul_vec_accum_gadget"),
|
|
|
+ // Precomputed coordinates of C
|
|
|
+ Cx(2),
|
|
|
+ Cy("4950745124018817972378217179409499695353526031437053848725554590521829916331"),
|
|
|
+ outx(outx), outy(outy), Ax(Ax), Ay(Ay), svec(svec), Ptable(Ptable)
|
|
|
+ {
|
|
|
+ size_t numbits = svec.size();
|
|
|
+ assert(Ptable.size() == 2*numbits);
|
|
|
+ accumx.allocate(this->pb, numbits-1, "accumx");
|
|
|
+ accumy.allocate(this->pb, numbits-1, "accumy");
|
|
|
+
|
|
|
+ for (size_t i = 0; i < numbits; ++i) {
|
|
|
+ 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, Ptable[2*i], Ptable[2*i+1]);
|
|
|
+
|
|
|
+ FieldT newAXSx, newAXSy;
|
|
|
+ ec_add_points(newAXSx, newAXSy, AXSx, AXSy, Cx, Cy);
|
|
|
+ AXSx = newAXSx;
|
|
|
+ AXSy = newAXSy;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void generate_r1cs_constraints()
|
|
|
+ {
|
|
|
+ for (auto&& gadget : twoadders) {
|
|
|
+ gadget.generate_r1cs_constraints();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void generate_r1cs_witness()
|
|
|
+ {
|
|
|
+ for (auto&& gadget : twoadders) {
|
|
|
+ gadget.generate_r1cs_witness();
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// Compute A + s*P as (outx, outy) for an accumulator A, a precomputed
|
|
|
+// addition table Ptable for a variable point P, and s given as a field
|
|
|
+// element. The _caller_ is responsible for proving that the elements
|
|
|
+// of svec are bits. The (constant) accumulator excess (AXS) will be
|
|
|
+// updated; when all the computations are complete, AXS should be
|
|
|
+// subtracted from the accumulator A. The addition table is a variable
|
|
|
+// array of length 2*numbits (where numbits is the length of the FieldT
|
|
|
+// size) such that Ptable[2*i] and Ptable[2*i+1] are the (x,y)
|
|
|
+// coordinates of 2^i * P + C.
|
|
|
+template<typename FieldT>
|
|
|
+class ec_scalarmul_accum_gadget : public gadget<FieldT> {
|
|
|
+private:
|
|
|
+ pb_variable_array<FieldT> svec;
|
|
|
+ std::vector<packing_gadget<FieldT> > packers;
|
|
|
+ std::vector<ec_scalarmul_vec_accum_gadget<FieldT> > vecgadget;
|
|
|
+
|
|
|
+public:
|
|
|
+ const pb_variable<FieldT> outx, outy;
|
|
|
+ const pb_variable<FieldT> Ax, Ay;
|
|
|
+ const pb_variable<FieldT> s;
|
|
|
+ const pb_variable_array<FieldT> Ptable;
|
|
|
+
|
|
|
+ ec_scalarmul_accum_gadget(protoboard<FieldT> &pb,
|
|
|
+ const pb_variable<FieldT> &outx,
|
|
|
+ const pb_variable<FieldT> &outy,
|
|
|
+ const pb_variable<FieldT> &Ax,
|
|
|
+ const pb_variable<FieldT> &Ay,
|
|
|
+ const pb_variable<FieldT> &s,
|
|
|
+ const pb_variable_array<FieldT> &Ptable,
|
|
|
+ FieldT &AXSx, FieldT &AXSy) :
|
|
|
+ gadget<FieldT>(pb, "ec_scalarmul_accum_gadget"),
|
|
|
+ outx(outx), outy(outy), Ax(Ax), Ay(Ay), s(s), Ptable(Ptable)
|
|
|
+ {
|
|
|
+ // Allocate variables to protoboard
|
|
|
+ // The strings (like "x") are only for debugging purposes
|
|
|
+
|
|
|
+ size_t numbits = FieldT::num_bits;
|
|
|
+ svec.allocate(this->pb, numbits, "svec");
|
|
|
+ packers.emplace_back(this->pb, svec, s);
|
|
|
+ vecgadget.emplace_back(this->pb, outx, outy, Ax, Ay, svec, Ptable, AXSx, AXSy);
|
|
|
+ }
|
|
|
+
|
|
|
+ void generate_r1cs_constraints()
|
|
|
+ {
|
|
|
+ packers[0].generate_r1cs_constraints(true);
|
|
|
+ vecgadget[0].generate_r1cs_constraints();
|
|
|
+ }
|
|
|
+
|
|
|
+ void generate_r1cs_witness()
|
|
|
+ {
|
|
|
+ packers[0].generate_r1cs_witness_from_packed();
|
|
|
+ vecgadget[0].generate_r1cs_witness();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// Compute s*P as (outx, outy) for a precomputed addition table Ptable
|
|
|
+// for a variable point P, and s given as a bit vector. The _caller_ is
|
|
|
+// responsible for proving that the elements of svec are bits.
|
|
|
+// The addition table is a variable array of length 2*numbits (where
|
|
|
+// numbits is the length of svec) such that Ptable[2*i] and
|
|
|
+// Ptable[2*i+1] are the (x,y) coordinates of 2^i * P + C.
|
|
|
+template<typename FieldT>
|
|
|
+class ec_scalarmul_vec_gadget : public gadget<FieldT> {
|
|
|
+private:
|
|
|
+ FieldT Cx, Cy, Ax, Ay, AXSx, AXSy;
|
|
|
+ pb_variable<FieldT> accinx, acciny, accoutx, accouty;
|
|
|
+ std::vector<ec_scalarmul_vec_accum_gadget<FieldT> > scalarmuls;
|
|
|
+ std::vector<ec_constant_add_gadget<FieldT> > adders;
|
|
|
+public:
|
|
|
+ const pb_variable<FieldT> outx, outy;
|
|
|
+ const pb_variable_array<FieldT> svec;
|
|
|
+ const pb_variable_array<FieldT> Ptable;
|
|
|
+
|
|
|
+ ec_scalarmul_vec_gadget(protoboard<FieldT> &pb,
|
|
|
+ const pb_variable<FieldT> &outx,
|
|
|
+ const pb_variable<FieldT> &outy,
|
|
|
+ const pb_variable_array<FieldT> &svec,
|
|
|
+ const pb_variable_array<FieldT> &Ptable) :
|
|
|
+ gadget<FieldT>(pb, "ec_scalarmul_vec_gadget"),
|
|
|
+ // Precomputed coordinates of C and A
|
|
|
+ Cx(2),
|
|
|
+ Cy("4950745124018817972378217179409499695353526031437053848725554590521829916331"),
|
|
|
+ Ax("7536839002660211356286040193441766649532044555061394833845553337792579131020"),
|
|
|
+ Ay("11391058648720923807988142436733355540810929560298907319389650598553246451302"),
|
|
|
+ outx(outx), outy(outy), svec(svec), Ptable(Ptable)
|
|
|
+ {
|
|
|
+ AXSx = Ax;
|
|
|
+ AXSy = Ay;
|
|
|
+ accinx.allocate(this->pb, "accinx");
|
|
|
+ acciny.allocate(this->pb, "acciny");
|
|
|
+ accoutx.allocate(this->pb, "accoutx");
|
|
|
+ accouty.allocate(this->pb, "accouty");
|
|
|
+
|
|
|
+ scalarmuls.emplace_back(pb, accoutx, accouty, accinx, acciny, svec, Ptable, AXSx, AXSy);
|
|
|
+ adders.emplace_back(pb, outx, outy, accoutx, accouty, AXSx, -AXSy);
|
|
|
+ }
|
|
|
+
|
|
|
+ void generate_r1cs_constraints()
|
|
|
+ {
|
|
|
+ this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(accinx, 1, Ax));
|
|
|
+ this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(acciny, 1, Ay));
|
|
|
+ scalarmuls[0].generate_r1cs_constraints();
|
|
|
+ adders[0].generate_r1cs_constraints();
|
|
|
+ }
|
|
|
+
|
|
|
+ void generate_r1cs_witness()
|
|
|
+ {
|
|
|
+ this->pb.val(accinx) = Ax;
|
|
|
+ this->pb.val(acciny) = Ay;
|
|
|
+ scalarmuls[0].generate_r1cs_witness();
|
|
|
+ adders[0].generate_r1cs_witness();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// Compute s*P as (outx, outy) for a precomputed addition table Ptable
|
|
|
+// for a variable point P, and s given as a field element. The addition
|
|
|
+// table is a variable array of length 2*numbits (where numbits is the
|
|
|
+// length of the FieldT size) such that Ptable[2*i] and Ptable[2*i+1]
|
|
|
+// are the (x,y) coordinates of 2^i * P + C.
|
|
|
+template<typename FieldT>
|
|
|
+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;
|
|
|
+
|
|
|
+public:
|
|
|
+ const pb_variable<FieldT> outx, outy;
|
|
|
+ const pb_variable<FieldT> s;
|
|
|
+ const pb_variable_array<FieldT> Ptable;
|
|
|
+
|
|
|
+ ec_scalarmul_gadget(protoboard<FieldT> &pb,
|
|
|
+ const pb_variable<FieldT> &outx,
|
|
|
+ const pb_variable<FieldT> &outy,
|
|
|
+ const pb_variable<FieldT> &s,
|
|
|
+ const pb_variable_array<FieldT> &Ptable) :
|
|
|
+ gadget<FieldT>(pb, "ec_scalarmul_gadget"),
|
|
|
+ outx(outx), outy(outy), s(s), Ptable(Ptable)
|
|
|
+ {
|
|
|
+ // Allocate variables to protoboard
|
|
|
+ // The strings (like "x") are only for debugging purposes
|
|
|
+
|
|
|
+ size_t numbits = FieldT::num_bits;
|
|
|
+ svec.allocate(this->pb, numbits, "svec");
|
|
|
+ packers.emplace_back(this->pb, svec, s);
|
|
|
+ vecgadget.emplace_back(this->pb, outx, outy, svec, Ptable);
|
|
|
+ }
|
|
|
+
|
|
|
+ void generate_r1cs_constraints()
|
|
|
+ {
|
|
|
+ packers[0].generate_r1cs_constraints(true);
|
|
|
+ vecgadget[0].generate_r1cs_constraints();
|
|
|
+ }
|
|
|
+
|
|
|
+ void generate_r1cs_witness()
|
|
|
+ {
|
|
|
+ packers[0].generate_r1cs_witness_from_packed();
|
|
|
+ vecgadget[0].generate_r1cs_witness();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
// Compute a*G + b*H as (outx, outy), given a and b as field elements.
|
|
|
template<typename FieldT>
|
|
|
class ec_pedersen_gadget : public gadget<FieldT> {
|