Browse Source

Start on scalarmuls of variable points

Ian Goldberg 4 years ago
parent
commit
5383110390
1 changed files with 287 additions and 4 deletions
  1. 287 4
      ecgadget.hpp

+ 287 - 4
ecgadget.hpp

@@ -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> {