Browse Source

Scalar multiples of variable points (with new varscalarmul test program)

Ian Goldberg 4 years ago
parent
commit
629d2245ec
3 changed files with 189 additions and 5 deletions
  1. 4 1
      Makefile
  2. 94 4
      ecgadget.hpp
  3. 91 0
      varscalarmul.cpp

+ 4 - 1
Makefile

@@ -1,4 +1,4 @@
-all: pedersen scalarmul
+all: pedersen scalarmul varscalarmul
 
 LIBSNARK=libsnark
 
@@ -12,6 +12,9 @@ pedersen: pedersen.cpp ecgadget.hpp libsnark_headers.hpp.gch pedersen.hpp.gch
 scalarmul: scalarmul.cpp ecgadget.hpp libsnark_headers.hpp.gch scalarmul.hpp.gch
 	g++ $(CXXFLAGS) -o scalarmul scalarmul.cpp $(LDFLAGS)
 
+varscalarmul: varscalarmul.cpp ecgadget.hpp libsnark_headers.hpp.gch scalarmul.hpp.gch
+	g++ $(CXXFLAGS) -o varscalarmul varscalarmul.cpp $(LDFLAGS)
+
 libsnark_headers.hpp.gch: libsnark_headers.hpp
 	g++ $(CXXFLAGS) $<
 

+ 94 - 4
ecgadget.hpp

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

+ 91 - 0
varscalarmul.cpp

@@ -0,0 +1,91 @@
+#include <stdlib.h>
+#include <iostream>
+#include <fstream>
+
+#include "ecgadget.hpp"
+#include "scalarmul.hpp"
+
+using namespace libsnark;
+using namespace std;
+
+int main()
+{
+  // Initialize the curve parameters
+
+  default_r1cs_gg_ppzksnark_pp::init_public_params();
+
+  typedef libff::Fr<default_r1cs_gg_ppzksnark_pp> FieldT;
+  
+  // Create protoboard
+
+  libff::start_profiling();
+
+  cout << "Keypair" << endl;
+
+  protoboard<FieldT> pb;
+  pb_variable<FieldT> outx, outy;
+  pb_variable<FieldT> s;
+  pb_variable_array<FieldT> Ptable;
+
+  // A variable base point P
+  const FieldT Px = FieldT("1095194319010475832867263440470707690447963461907735667341232728633587089702");
+  const FieldT Py = FieldT("9185463202887631101218413269806857706246311016297504828581985913021301344974");
+
+  // Allocate variables
+
+  size_t numbits = FieldT::num_bits;
+  outx.allocate(pb, "outx");
+  outy.allocate(pb, "outy");
+  Ptable.allocate(pb, 2*numbits, "Ptable");
+  s.allocate(pb, "s");
+
+  // This sets up the protoboard variables so that the first n of them
+  // represent the public input and the rest is private input
+
+  pb.set_input_sizes(2+2*numbits);
+
+  // Initialize the gadget
+  ec_scalarmul_gadget<FieldT> sm(pb, outx, outy, s, Ptable);
+  sm.generate_r1cs_constraints();
+
+  const r1cs_constraint_system<FieldT> constraint_system = pb.get_constraint_system();
+
+  const r1cs_gg_ppzksnark_keypair<default_r1cs_gg_ppzksnark_pp> keypair = r1cs_gg_ppzksnark_generator<default_r1cs_gg_ppzksnark_pp>(constraint_system);
+
+  // Add witness values
+
+  cout << "Prover" << endl;
+  
+  pb.val(s) = FieldT::random_element();
+  cout << "Computing " << pb.val(s) << "*G" << endl;
+
+  ec_scalarmul_gadget<FieldT>::compute_Ptable(pb, Ptable, Px, Py);
+  sm.generate_r1cs_witness();
+
+  const r1cs_gg_ppzksnark_proof<default_r1cs_gg_ppzksnark_pp> proof = r1cs_gg_ppzksnark_prover<default_r1cs_gg_ppzksnark_pp>(keypair.pk, pb.primary_input(), pb.auxiliary_input());
+
+  cout << "Verifier" << endl;
+
+  bool verified = r1cs_gg_ppzksnark_verifier_strong_IC<default_r1cs_gg_ppzksnark_pp>(keypair.vk, pb.primary_input(), proof);
+
+  cout << "Number of R1CS constraints: " << constraint_system.num_constraints() << endl;
+  cout << "Primary (public) input: " << pb.primary_input() << endl;
+  cout << "Auxiliary (private) input length: " << pb.auxiliary_input().size() << endl;
+//  cout << "Auxiliary (private) input: " << pb.auxiliary_input() << endl;
+  cout << "Verification status: " << verified << endl;
+
+  ofstream pkfile("pk_varscalarmul");
+  pkfile << keypair.pk;
+  pkfile.close();
+  ofstream vkfile("vk_varscalarmul");
+  vkfile << keypair.vk;
+  vkfile.close();
+  ofstream pffile("proof_varscalarmul");
+  pffile << proof;
+  pffile.close();
+
+  cout << pb.val(s) << "*P" << " = (" << pb.val(outx) << ", " << pb.val(outy) << ")" << endl;
+
+
+  return 0;
+}