|
@@ -2,7 +2,18 @@
|
|
|
|
|
|
using namespace libsnark;
|
|
|
|
|
|
-// Double a public EC point (inx,iny) to yield (outx,outy). The input
|
|
|
+// There are two types of values:
|
|
|
+// _constants_ are values known at circuit generation time; they
|
|
|
+// are global constants known to everyone
|
|
|
+// _variables_ are values that change in each use of the circuit;
|
|
|
+// they have two subtypes:
|
|
|
+//
|
|
|
+// _public variables_ are values known to both the prover
|
|
|
+// and verifier but change in each use of the circuit
|
|
|
+// _private variables_ are values known only to the prover
|
|
|
+// and change in each use of the circuit
|
|
|
+
|
|
|
+// Double a constant EC point (inx,iny) to yield (outx,outy). The input
|
|
|
// point must not be the point at infinity.
|
|
|
template<typename FieldT>
|
|
|
static void ec_double_point(FieldT &outx, FieldT &outy,
|
|
@@ -14,7 +25,7 @@ static void ec_double_point(FieldT &outx, FieldT &outy,
|
|
|
outy = lambda * (inx - outx) - iny;
|
|
|
}
|
|
|
|
|
|
-// Add public EC points (inx, iny) and (addx, addy) to yield (outx, outy).
|
|
|
+// Add constant EC points (inx, iny) and (addx, addy) to yield (outx, outy).
|
|
|
// inx and addx must not be equal.
|
|
|
template<typename FieldT>
|
|
|
static void ec_add_points(FieldT &outx, FieldT &outy,
|
|
@@ -26,8 +37,8 @@ static void ec_add_points(FieldT &outx, FieldT &outy,
|
|
|
outy = lambda * (inx - outx) - iny;
|
|
|
}
|
|
|
|
|
|
-// Double the EC point (inx,iny) to yield (outx,outy). The input point
|
|
|
-// must not be the point at infinity.
|
|
|
+// Double the variable EC point (inx,iny) to yield (outx,outy). The
|
|
|
+// input point must not be the point at infinity.
|
|
|
template<typename FieldT>
|
|
|
class ec_double_gadget : public gadget<FieldT> {
|
|
|
private:
|
|
@@ -38,8 +49,8 @@ public:
|
|
|
ec_double_gadget(protoboard<FieldT> &pb,
|
|
|
const pb_variable<FieldT> &outx,
|
|
|
const pb_variable<FieldT> &outy,
|
|
|
- const pb_variable<FieldT> &inx,
|
|
|
- const pb_variable<FieldT> &iny) :
|
|
|
+ const pb_linear_combination<FieldT> &inx,
|
|
|
+ const pb_linear_combination<FieldT> &iny) :
|
|
|
gadget<FieldT>(pb, "ec_double_gadget"), outx(outx), outy(outy),
|
|
|
inx(inx), iny(iny)
|
|
|
{
|
|
@@ -68,15 +79,16 @@ public:
|
|
|
|
|
|
void generate_r1cs_witness()
|
|
|
{
|
|
|
- this->pb.val(inxsq) = this->pb.val(inx) * this->pb.val(inx);
|
|
|
- this->pb.val(lambda) = (this->pb.val(inxsq) * 3 - 3) * (this->pb.val(iny) * 2).inverse();
|
|
|
- this->pb.val(outx) = this->pb.val(lambda).squared() - this->pb.val(inx) * 2;
|
|
|
- this->pb.val(outy) = this->pb.val(lambda) * (this->pb.val(inx) - this->pb.val(outx)) - this->pb.val(iny);
|
|
|
+ this->pb.val(inxsq) = this->pb.lc_val(inx) * this->pb.lc_val(inx);
|
|
|
+ this->pb.val(lambda) = (this->pb.val(inxsq) * 3 - 3) * (this->pb.lc_val(iny) * 2).inverse();
|
|
|
+ this->pb.val(outx) = this->pb.val(lambda).squared() - this->pb.lc_val(inx) * 2;
|
|
|
+ this->pb.val(outy) = this->pb.val(lambda) * (this->pb.lc_val(inx) - this->pb.val(outx)) - this->pb.lc_val(iny);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-// Add the EC point (addx,addy) to the EC point (inx,iny) to yield
|
|
|
-// (outx,outy). The input point must not be the point at infinity.
|
|
|
+// Add the variable EC point (addx,addy) to the variable EC point
|
|
|
+// (inx,iny) to yield (outx,outy). The input point must not be the
|
|
|
+// point at infinity.
|
|
|
template<typename FieldT>
|
|
|
class ec_add_gadget : public gadget<FieldT> {
|
|
|
private:
|
|
@@ -122,10 +134,11 @@ public:
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-// Add the public EC point P to the EC point (inx,iny) to yield
|
|
|
-// (outx,outy). The input point must not be the point at infinity.
|
|
|
+// Add the variable EC point P to the constant EC point (inx,iny) to
|
|
|
+// yield (outx,outy). The input point must not be the point at
|
|
|
+// infinity.
|
|
|
template<typename FieldT>
|
|
|
-class ec_public_add_gadget : public gadget<FieldT> {
|
|
|
+class ec_constant_add_gadget : public gadget<FieldT> {
|
|
|
private:
|
|
|
pb_variable<FieldT> lambda;
|
|
|
public:
|
|
@@ -133,13 +146,13 @@ public:
|
|
|
const pb_linear_combination<FieldT> inx, iny;
|
|
|
const FieldT Px, Py;
|
|
|
|
|
|
- ec_public_add_gadget(protoboard<FieldT> &pb,
|
|
|
+ ec_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 FieldT &Px, const FieldT &Py) :
|
|
|
- gadget<FieldT>(pb, "ec_public_add_gadget"),
|
|
|
+ gadget<FieldT>(pb, "ec_constant_add_gadget"),
|
|
|
outx(outx), outy(outy), inx(inx), iny(iny), Px(Px), Py(Py)
|
|
|
{
|
|
|
// Allocate variables to protoboard
|
|
@@ -169,29 +182,29 @@ public:
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-// Add nothing or the public EC point P to the EC point (inx,iny) to
|
|
|
-// yield (outx,outy). The input point must not be the point at
|
|
|
-// infinity. The input bit do_add controls whether the addition is
|
|
|
-// done.
|
|
|
+// Add nothing or the constant EC point P to the variable EC point
|
|
|
+// (inx,iny) to yield (outx,outy). The input point must not be the
|
|
|
+// point at infinity. The input bit do_add controls whether the
|
|
|
+// addition is done.
|
|
|
template<typename FieldT>
|
|
|
-class ec_conditional_add_gadget : public gadget<FieldT> {
|
|
|
+class ec_conditional_constant_add_gadget : public gadget<FieldT> {
|
|
|
private:
|
|
|
pb_variable<FieldT> sumx, sumy;
|
|
|
- std::vector<ec_public_add_gadget<FieldT> > adder;
|
|
|
+ std::vector<ec_constant_add_gadget<FieldT> > adder;
|
|
|
public:
|
|
|
const pb_variable<FieldT> outx, outy;
|
|
|
const pb_linear_combination<FieldT> inx, iny;
|
|
|
const pb_variable<FieldT> do_add;
|
|
|
const FieldT Px, Py;
|
|
|
|
|
|
- ec_conditional_add_gadget(protoboard<FieldT> &pb,
|
|
|
+ ec_conditional_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> &do_add,
|
|
|
const FieldT &Px, const FieldT &Py) :
|
|
|
- gadget<FieldT>(pb, "ec_conditional_add_gadget"),
|
|
|
+ gadget<FieldT>(pb, "ec_conditional_constant_add_gadget"),
|
|
|
outx(outx), outy(outy), inx(inx), iny(iny), do_add(do_add),
|
|
|
Px(Px), Py(Py)
|
|
|
{
|
|
@@ -233,11 +246,11 @@ public:
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-// Add nothing, or one of the public EC points P1, P2, or P3 to the EC
|
|
|
+// 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 adds simultaneously in just 6 constraints.
|
|
|
+// does two conditional constant adds simultaneously in just 6 constraints.
|
|
|
template<typename FieldT>
|
|
|
class ec_add_P123_gadget : public gadget<FieldT> {
|
|
|
private:
|
|
@@ -321,41 +334,42 @@ public:
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-// Compute a*P as (outx, outy) for a given public point P, given a
|
|
|
+// Compute a*P as (outx, outy) for a given constant point P, given a
|
|
|
// as a bit vector. The _caller_ is responsible for proving that the
|
|
|
// elements of avec are bits.
|
|
|
template<typename FieldT>
|
|
|
-class ec_scalarmul_vec_gadget : public gadget<FieldT> {
|
|
|
+class ec_constant_scalarmul_vec_gadget : public gadget<FieldT> {
|
|
|
private:
|
|
|
FieldT Cx, Cy, CPx, CPy;
|
|
|
pb_variable_array<FieldT> accumx, accumy;
|
|
|
std::vector<ec_add_P123_gadget<FieldT> > conddoubleadders;
|
|
|
- std::vector<ec_conditional_add_gadget<FieldT> > condsingleadders;
|
|
|
- std::vector<ec_public_add_gadget<FieldT> > singleadders;
|
|
|
+ std::vector<ec_conditional_constant_add_gadget<FieldT> > condsingleadders;
|
|
|
+ std::vector<ec_constant_add_gadget<FieldT> > singleadders;
|
|
|
public:
|
|
|
const pb_variable<FieldT> outx, outy;
|
|
|
const pb_variable_array<FieldT> avec;
|
|
|
const FieldT Px, Py;
|
|
|
|
|
|
- // Strategy: We compute (in public) (powers of 2) times P, and then
|
|
|
- // conditionally add them into an accumulator. Because our adder cannot
|
|
|
- // handle the point at infinity O, we start the accumulator with a value
|
|
|
- // of C, whose discrete log with respect to P should be unknown, so that
|
|
|
- // we won't encounter O along the way. (Also, a should not be 0 or
|
|
|
- // the group order.) We actually start the accumulator with either
|
|
|
- // C or C+P depending on avec[0], so we get the first conditional add
|
|
|
- // "for free". Then we use the ec_add_P123_gadget to do the conditional
|
|
|
- // adds two at a time (at a cost of 6 constraints per pair, as opposed to
|
|
|
- // 5 for a single conditional add). If the length of avec is even, then
|
|
|
- // there will be one left over, and we do a single conditional add for
|
|
|
- // that one. Finally, we add the public point -C.
|
|
|
-
|
|
|
- ec_scalarmul_vec_gadget(protoboard<FieldT> &pb,
|
|
|
+ // Strategy: We compute (as compile-time constants) (powers of 2)
|
|
|
+ // times P, and then conditionally add them into an accumulator.
|
|
|
+ // Because our adder cannot handle the point at infinity O, we start
|
|
|
+ // the accumulator with a value of C, whose discrete log with respect
|
|
|
+ // to P should be unknown, so that we won't encounter O along the way.
|
|
|
+ // (Also, a should not be 0 or the group order.) We actually start
|
|
|
+ // the accumulator with either C or C+P depending on avec[0], so we
|
|
|
+ // get the first conditional add "for free". Then we use the
|
|
|
+ // ec_add_P123_gadget to do the conditional adds two at a time (at a
|
|
|
+ // cost of 6 constraints per pair, as opposed to 5 for a single
|
|
|
+ // conditional add). If the length of avec is even, then there will
|
|
|
+ // be one left over, and we do a single conditional add for that one.
|
|
|
+ // Finally, we add the public point -C.
|
|
|
+
|
|
|
+ ec_constant_scalarmul_vec_gadget(protoboard<FieldT> &pb,
|
|
|
const pb_variable<FieldT> &outx,
|
|
|
const pb_variable<FieldT> &outy,
|
|
|
const pb_variable_array<FieldT> &avec,
|
|
|
const FieldT &Px, const FieldT &Py) :
|
|
|
- gadget<FieldT>(pb, "ec_pedersen_vec_gadget"),
|
|
|
+ gadget<FieldT>(pb, "ec_constant_scalarmul_vec_gadget"),
|
|
|
// Precomputed coordinates of C
|
|
|
Cx(2),
|
|
|
Cy("4950745124018817972378217179409499695353526031437053848725554590521829916331"),
|
|
@@ -440,25 +454,25 @@ public:
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-// Compute a*P as (outx, outy) for a given public point P, given a
|
|
|
+// Compute a*P as (outx, outy) for a given constant point P, given a
|
|
|
// as a field element.
|
|
|
template<typename FieldT>
|
|
|
-class ec_scalarmul_gadget : public gadget<FieldT> {
|
|
|
+class ec_constant_scalarmul_gadget : public gadget<FieldT> {
|
|
|
private:
|
|
|
pb_variable_array<FieldT> avec;
|
|
|
std::vector<packing_gadget<FieldT> > packers;
|
|
|
- std::vector<ec_scalarmul_vec_gadget<FieldT> > vecgadget;
|
|
|
+ std::vector<ec_constant_scalarmul_vec_gadget<FieldT> > vecgadget;
|
|
|
|
|
|
public:
|
|
|
const pb_variable<FieldT> outx, outy, a;
|
|
|
const FieldT Px, Py;
|
|
|
|
|
|
- ec_scalarmul_gadget(protoboard<FieldT> &pb,
|
|
|
+ ec_constant_scalarmul_gadget(protoboard<FieldT> &pb,
|
|
|
const pb_variable<FieldT> &outx,
|
|
|
const pb_variable<FieldT> &outy,
|
|
|
const pb_variable<FieldT> &a,
|
|
|
const FieldT &Px, const FieldT &Py) :
|
|
|
- gadget<FieldT>(pb, "ec_scalarmul_gadget"),
|
|
|
+ gadget<FieldT>(pb, "ec_constant_scalarmul_gadget"),
|
|
|
outx(outx), outy(outy), a(a), Px(Px), Py(Py)
|
|
|
{
|
|
|
// Allocate variables to protoboard
|
|
@@ -483,215 +497,12 @@ public:
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-// Compute a*G + b*H as (outx, outy), given a and b as bit vectors.
|
|
|
-// a and b must be of the same size. The _caller_ is responsible for
|
|
|
-// proving that the elements of avec and bvec are bits.
|
|
|
-template<typename FieldT>
|
|
|
-class ec_pedersen_vec_gadget : public gadget<FieldT> {
|
|
|
-private:
|
|
|
- pb_variable_array<FieldT> accumx, accumy, daccumx, daccumy;
|
|
|
- pb_variable<FieldT> lambda;
|
|
|
- std::vector<ec_double_gadget<FieldT> > doublers;
|
|
|
- std::vector<ec_add_P123_gadget<FieldT> > adders;
|
|
|
- const FieldT Cx, Cy, CGx, CGy, CHx, CHy, CGHx, CGHy;
|
|
|
- FieldT m2nCx, m2nCy;
|
|
|
-
|
|
|
- // Compute m2nC = -2^n * C. We can precomute the answers for values
|
|
|
- // of n we expect to get.
|
|
|
- void compute_m2nC(FieldT &m2nCx, FieldT &m2nCy, size_t n)
|
|
|
- {
|
|
|
- if (n == 253) {
|
|
|
- // Precomputed coordinates of -2^253*C
|
|
|
- m2nCx = FieldT("2630025903576807331238993847875694711243784786568881628418508626984487096258");
|
|
|
- m2nCy = FieldT("17628834417659968531880949658739649785248429713924280788649629869316127047701");
|
|
|
- } else {
|
|
|
- // Invariant: m2iC = -2^i * C
|
|
|
- FieldT m2iCx = Cx;
|
|
|
- FieldT m2iCy = -Cy;
|
|
|
- size_t i = 0;
|
|
|
- while (i < n) {
|
|
|
- FieldT m2iCxo, m2iCyo;
|
|
|
- ec_double_point(m2iCxo, m2iCyo, m2iCx, m2iCy);
|
|
|
- m2iCx = m2iCxo;
|
|
|
- m2iCy = m2iCyo;
|
|
|
- ++i;
|
|
|
- }
|
|
|
- m2nCx = m2iCx;
|
|
|
- m2nCy = m2iCy;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-public:
|
|
|
- const pb_variable<FieldT> outx, outy;
|
|
|
- const pb_variable_array<FieldT> avec, bvec;
|
|
|
-
|
|
|
- ec_pedersen_vec_gadget(protoboard<FieldT> &pb,
|
|
|
- const pb_variable<FieldT> &outx,
|
|
|
- const pb_variable<FieldT> &outy,
|
|
|
- const pb_variable_array<FieldT> &avec,
|
|
|
- const pb_variable_array<FieldT> &bvec) :
|
|
|
- gadget<FieldT>(pb, "ec_pedersen_vec_gadget"),
|
|
|
- // Precomputed coordinates of C, C+G, C+H, and C+G+H
|
|
|
- Cx(2),
|
|
|
- Cy("4950745124018817972378217179409499695353526031437053848725554590521829916331"),
|
|
|
- CGx("4998993376791159436553350546778310121346937620672073819457843493128326049156"),
|
|
|
- CGy("11119675827304465476900978353730540420130346377889406728458325551400357147144"),
|
|
|
- CHx("19614539896004018833724771305328960655474424364705508053472946746883341111010"),
|
|
|
- CHy("9853241351900213537247225242092949438866383394579783148395572971112906592855"),
|
|
|
- CGHx("10755582242294898568680134375159803731902153202607833320871336755950640390928"),
|
|
|
- CGHy("3110667473759844579409644567672992116704859238881299917617768683686288881761"),
|
|
|
- outx(outx), outy(outy), avec(avec), bvec(bvec)
|
|
|
- {
|
|
|
- // Allocate variables to protoboard
|
|
|
- // The strings (like "x") are only for debugging purposes
|
|
|
-
|
|
|
- size_t numbits = avec.size();
|
|
|
- accumx.allocate(this->pb, numbits, "accumx");
|
|
|
- accumy.allocate(this->pb, numbits, "accumy");
|
|
|
- daccumx.allocate(this->pb, numbits-1, "daccumx");
|
|
|
- daccumy.allocate(this->pb, numbits-1, "daccumy");
|
|
|
- lambda.allocate(this->pb, "lambda");
|
|
|
-
|
|
|
- for (size_t i = 0; i < numbits-1; ++i) {
|
|
|
- doublers.emplace_back(this->pb, daccumx[i], daccumy[i],
|
|
|
- accumx[i], accumy[i]);
|
|
|
- adders.emplace_back(this->pb, accumx[i+1], accumy[i+1],
|
|
|
- daccumx[i], daccumy[i], avec[numbits-2-i], bvec[numbits-2-i],
|
|
|
- // The coordinates of G, H, and G+H
|
|
|
- FieldT(0), FieldT("11977228949870389393715360594190192321220966033310912010610740966317727761886"),
|
|
|
- FieldT(1), FieldT("21803877843449984883423225223478944275188924769286999517937427649571474907279"),
|
|
|
- FieldT("2864090850787705444524344020850508438903451433901276387624248428140647539638"),
|
|
|
- FieldT("3350168998338968221269367365107720885864670493693161027931048546881356285970"));
|
|
|
- }
|
|
|
-
|
|
|
- compute_m2nC(m2nCx, m2nCy, numbits-1);
|
|
|
- }
|
|
|
-
|
|
|
- void generate_r1cs_constraints()
|
|
|
- {
|
|
|
- // Strategy: We do a basic double-and-add, using the variant of a
|
|
|
- // single double and an add of one of (O, G, H, G+H) at each step.
|
|
|
- // *However*, there's a twist. Our doubling and adding routines
|
|
|
- // don't handle the point at infinity O as the point to add to or to
|
|
|
- // double. (Adding O as one of the four options above is fine.)
|
|
|
- // Normally, the double-and-add algorithm starts with an accumulator
|
|
|
- // of O, and that won't work for us. So instead, we start the
|
|
|
- // accumulator at a different base point C, whose discrete log
|
|
|
- // with respect to the (G,H) basis is unknown. Then we'll end up
|
|
|
- // with an extra 2^n * C in the accumulator (where n is the number
|
|
|
- // of doublings we do), so at the end, we'll add the (constant!)
|
|
|
- // point -2^n * C to get the final result. That the discrete log of
|
|
|
- // C is unknown means we won't encounter O along the way, either (if
|
|
|
- // we did, we could compute the DL of C in the (G,H) basis).
|
|
|
-
|
|
|
- // For the first bit, we just precompute C, C+G, C+H, C+G+H (the
|
|
|
- // values are above) and use the top bit of a and b to choose which
|
|
|
- // one to start with.
|
|
|
-
|
|
|
- // accumx[0] = Cx + (CGx - Cx) * avec[numbits-1] + (CHx - Cx) *
|
|
|
- // bvec[numbits-1] + (CGHx - CGx - CHx + Cx) *
|
|
|
- // avec[numbits-1]*bvec[numbits-1] (and similarly for y)
|
|
|
-
|
|
|
- // We could possibly optimize this later by computing the a*b
|
|
|
- // product once, but then we'd have to pass a large linear
|
|
|
- // combination to a gadget, which it probably doesn't like? It
|
|
|
- // would save just one constraint, so probably not so important?
|
|
|
- size_t numbits = avec.size();
|
|
|
- this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>((CGHx - CGx - CHx + Cx) * avec[numbits-1], bvec[numbits-1], accumx[0] - (Cx + (CGx - Cx) * avec[numbits-1] + (CHx - Cx) * bvec[numbits-1])));
|
|
|
- this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>((CGHy - CGy - CHy + Cy) * avec[numbits-1], bvec[numbits-1], accumy[0] - (Cy + (CGy - Cy) * avec[numbits-1] + (CHy - Cy) * bvec[numbits-1])));
|
|
|
-
|
|
|
- // After that, for each remaining bit of a and b, we use the
|
|
|
- // ec_double_gadget and the ec_add_GH_gadget to accumulate
|
|
|
- // the answer.
|
|
|
- for (size_t i = 0; i < numbits-1; ++i) {
|
|
|
- doublers[i].generate_r1cs_constraints();
|
|
|
- adders[i].generate_r1cs_constraints();
|
|
|
- }
|
|
|
-
|
|
|
- // Finally, we add the constant point -2^n * C to the result, where
|
|
|
- // n = numbits-1
|
|
|
- // (m2nCx - accumx[numbits-1]) * lambda = m2nCy - accumy[numbits-1]
|
|
|
- this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(m2nCx - accumx[numbits-1], lambda, m2nCy - accumy[numbits-1]));
|
|
|
- // outx = lambda^2 - (m2nCx + accumx[numbits-1])
|
|
|
- this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(lambda, lambda, outx + m2nCx + accumx[numbits-1]));
|
|
|
- // outy = lambda * (accumx[numbits-1] - outx) - accumy[numbits-1]
|
|
|
- this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(lambda, accumx[numbits-1] - outx, outy + accumy[numbits-1]));
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- void generate_r1cs_witness()
|
|
|
- {
|
|
|
- size_t numbits = avec.size();
|
|
|
- this->pb.val(accumx[0]) = Cx + (CGx - Cx) * this->pb.val(avec[numbits-1]) + (CHx - Cx) * this->pb.val(bvec[numbits-1]) + (CGHx - CGx - CHx + Cx) * this->pb.val(avec[numbits-1])*this->pb.val(bvec[numbits-1]);
|
|
|
- this->pb.val(accumy[0]) = Cy + (CGy - Cy) * this->pb.val(avec[numbits-1]) + (CHy - Cy) * this->pb.val(bvec[numbits-1]) + (CGHy - CGy - CHy + Cy) * this->pb.val(avec[numbits-1])*this->pb.val(bvec[numbits-1]);
|
|
|
-
|
|
|
- for (size_t i = 0; i < numbits-1; ++i) {
|
|
|
- doublers[i].generate_r1cs_witness();
|
|
|
- adders[i].generate_r1cs_witness();
|
|
|
- }
|
|
|
-
|
|
|
- this->pb.val(lambda) = (m2nCy - this->pb.val(accumy[numbits-1])) *
|
|
|
- (m2nCx - this->pb.val(accumx[numbits-1])).inverse();
|
|
|
- this->pb.val(outx) = this->pb.val(lambda).squared() -
|
|
|
- (m2nCx + this->pb.val(accumx[numbits-1]));
|
|
|
- this->pb.val(outy) = this->pb.val(lambda) *
|
|
|
- (this->pb.val(accumx[numbits-1]) - this->pb.val(outx))
|
|
|
- - this->pb.val(accumy[numbits-1]);
|
|
|
-
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// Compute a*G + b*H as (outx, outy), given a and b as field elements.
|
|
|
-template<typename FieldT>
|
|
|
-class ec_old_pedersen_gadget : public gadget<FieldT> {
|
|
|
-private:
|
|
|
- pb_variable_array<FieldT> avec, bvec;
|
|
|
- std::vector<packing_gadget<FieldT> > packers;
|
|
|
- std::vector<ec_pedersen_vec_gadget<FieldT> > vecgadget;
|
|
|
-
|
|
|
-public:
|
|
|
- const pb_variable<FieldT> outx, outy, a, b;
|
|
|
-
|
|
|
- ec_old_pedersen_gadget(protoboard<FieldT> &pb,
|
|
|
- const pb_variable<FieldT> &outx,
|
|
|
- const pb_variable<FieldT> &outy,
|
|
|
- const pb_variable<FieldT> &a,
|
|
|
- const pb_variable<FieldT> &b) :
|
|
|
- gadget<FieldT>(pb, "ec_old_pedersen_gadget"),
|
|
|
- outx(outx), outy(outy), a(a), b(b)
|
|
|
- {
|
|
|
- // Allocate variables to protoboard
|
|
|
- // The strings (like "x") are only for debugging purposes
|
|
|
-
|
|
|
- size_t numbits = FieldT::num_bits;
|
|
|
- avec.allocate(this->pb, numbits, "avec");
|
|
|
- bvec.allocate(this->pb, numbits, "bvec");
|
|
|
- packers.emplace_back(this->pb, avec, a);
|
|
|
- packers.emplace_back(this->pb, bvec, b);
|
|
|
- vecgadget.emplace_back(this->pb, outx, outy, avec, bvec);
|
|
|
- }
|
|
|
-
|
|
|
- void generate_r1cs_constraints()
|
|
|
- {
|
|
|
- packers[0].generate_r1cs_constraints(true);
|
|
|
- packers[1].generate_r1cs_constraints(true);
|
|
|
- vecgadget[0].generate_r1cs_constraints();
|
|
|
- }
|
|
|
-
|
|
|
- void generate_r1cs_witness()
|
|
|
- {
|
|
|
- packers[0].generate_r1cs_witness_from_packed();
|
|
|
- packers[1].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> {
|
|
|
private:
|
|
|
pb_variable<FieldT> aoutx, aouty, boutx, bouty;
|
|
|
- std::vector<ec_scalarmul_gadget<FieldT> > mulgadgets;
|
|
|
+ std::vector<ec_constant_scalarmul_gadget<FieldT> > mulgadgets;
|
|
|
std::vector<ec_add_gadget<FieldT> > addgadget;
|
|
|
const FieldT Gx, Gy, Hx, Hy;
|
|
|
|