Browse Source

Make notation consistent for constants vs public variables, and remove some old dead code

Ian Goldberg 4 years ago
parent
commit
eb4d4d028b
2 changed files with 67 additions and 256 deletions
  1. 66 255
      ecgadget.hpp
  2. 1 1
      scalarmul.cpp

+ 66 - 255
ecgadget.hpp

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

+ 1 - 1
scalarmul.cpp

@@ -39,7 +39,7 @@ int main()
 
   // Initialize gadget
 
-  ec_scalarmul_gadget<FieldT> sm(pb, outx, outy, a, FieldT(0), FieldT("11977228949870389393715360594190192321220966033310912010610740966317727761886"));
+  ec_constant_scalarmul_gadget<FieldT> sm(pb, outx, outy, a, FieldT(0), FieldT("11977228949870389393715360594190192321220966033310912010610740966317727761886"));
   sm.generate_r1cs_constraints();
   
   const r1cs_constraint_system<FieldT> constraint_system = pb.get_constraint_system();