verifenc.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. #include <stdlib.h>
  2. #include <iostream>
  3. #include <fstream>
  4. #include "ecgadget.hpp"
  5. #include "scalarmul.hpp"
  6. using namespace libsnark;
  7. using namespace std;
  8. typedef enum {
  9. MODE_NONE,
  10. MODE_PRIV,
  11. MODE_PUB,
  12. MODE_CONST
  13. } Mode;
  14. template<typename FieldT>
  15. class verified_encryption_gadget : public gadget<FieldT> {
  16. private:
  17. const size_t numbits;
  18. FieldT curve_b, Gx, Gy, Hx, Hy;
  19. pb_variable<FieldT> r;
  20. pb_variable<FieldT> xsquared, ysquared;
  21. pb_variable_array<FieldT> kbits, rbits;
  22. pb_variable<FieldT> elgx, elgy;
  23. pb_linear_combination<FieldT> x;
  24. vector<packing_gadget<FieldT> > packers;
  25. vector<ec_constant_scalarmul_vec_gadget<FieldT> > constmuls;
  26. vector<ec_scalarmul_vec_gadget<FieldT> > muls;
  27. vector<ec_add_gadget<FieldT> > adders;
  28. public:
  29. const Mode mode;
  30. const pb_variable<FieldT> C1x, C1y, C2x, C2y, Kx, Ky;
  31. const pb_variable<FieldT> Px, Py;
  32. const pb_variable_array<FieldT> Ptable;
  33. const pb_variable<FieldT> k, s, y;
  34. verified_encryption_gadget(protoboard<FieldT> &pb,
  35. Mode mode,
  36. const pb_variable<FieldT> &C1x,
  37. const pb_variable<FieldT> &C1y,
  38. const pb_variable<FieldT> &C2x,
  39. const pb_variable<FieldT> &C2y,
  40. const pb_variable<FieldT> &Kx,
  41. const pb_variable<FieldT> &Ky,
  42. const pb_variable<FieldT> &Px,
  43. const pb_variable<FieldT> &Py,
  44. const pb_variable_array<FieldT> &Ptable,
  45. const pb_variable<FieldT> &k,
  46. const pb_variable<FieldT> &s,
  47. const pb_variable<FieldT> &y) :
  48. gadget<FieldT>(pb, "verified_encryption_gadget"),
  49. // Curve parameters and generators
  50. numbits(FieldT::num_bits),
  51. curve_b("7950939520449436327800262930799465135910802758673292356620796789196167463969"),
  52. Gx(0), Gy("11977228949870389393715360594190192321220966033310912010610740966317727761886"),
  53. Hx(1), Hy("21803877843449984883423225223478944275188924769286999517937427649571474907279"),
  54. mode(mode), C1x(C1x), C1y(C1y), C2x(C2x), C2y(C2y),
  55. Kx(Kx), Ky(Ky), Px(Px), Py(Py), Ptable(Ptable),
  56. k(k), s(s), y(y)
  57. {
  58. r.allocate(pb, "r");
  59. xsquared.allocate(pb, "xsquared");
  60. ysquared.allocate(pb, "ysquared");
  61. kbits.allocate(pb, numbits-8, "kbits");
  62. rbits.allocate(pb, numbits, "rbits");
  63. // The unpacking gadgets to turn k and r into bits
  64. packers.emplace_back(pb, kbits, k);
  65. packers.emplace_back(pb, rbits, r);
  66. // The El Gamal first component r*G
  67. constmuls.emplace_back(pb, C1x, C1y, rbits, Gx, Gy);
  68. // The El Gamal intermediate value r*P
  69. elgx.allocate(pb, "elgx");
  70. elgy.allocate(pb, "elgy");
  71. if (mode == MODE_CONST) {
  72. constmuls.emplace_back(pb, elgx, elgy, rbits, Hx, Hy);
  73. } else {
  74. muls.emplace_back(pb, elgx, elgy, rbits, Px, Py, Ptable, mode == MODE_PRIV, true);
  75. }
  76. // The El Gamal second component r*P + M
  77. x.assign(pb, k * 256 + s);
  78. adders.emplace_back(pb, C2x, C2y, elgx, elgy, x, y);
  79. // The generated public key k*G
  80. constmuls.emplace_back(pb, Kx, Ky, kbits, Gx, Gy);
  81. }
  82. void generate_r1cs_constraints()
  83. {
  84. // Prove (256*k+s,y) is on the curve
  85. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(y, y, ysquared));
  86. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(k * 256 + s, k * 256 + s, xsquared));
  87. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(xsquared - 3, k * 256 + s, ysquared - curve_b));
  88. for (auto&& gadget : packers) {
  89. gadget.generate_r1cs_constraints(true);
  90. }
  91. for (auto&& gadget : constmuls) {
  92. gadget.generate_r1cs_constraints();
  93. }
  94. for (auto&& gadget : muls) {
  95. gadget.generate_r1cs_constraints();
  96. }
  97. for (auto&& gadget : adders) {
  98. gadget.generate_r1cs_constraints();
  99. }
  100. }
  101. void generate_r1cs_witness()
  102. {
  103. this->pb.val(r) = FieldT::random_element();
  104. this->pb.val(xsquared) = (this->pb.val(k) * 256 + this->pb.val(s)).squared();
  105. this->pb.val(ysquared) = this->pb.val(y).squared();
  106. x.evaluate(this->pb);
  107. for (auto&& gadget : packers) {
  108. gadget.generate_r1cs_witness_from_packed();
  109. }
  110. for (auto&& gadget : constmuls) {
  111. gadget.generate_r1cs_witness();
  112. }
  113. for (auto&& gadget : muls) {
  114. gadget.generate_r1cs_witness();
  115. }
  116. for (auto&& gadget : adders) {
  117. gadget.generate_r1cs_witness();
  118. }
  119. }
  120. };
  121. int main(int argc, char **argv)
  122. {
  123. Mode mode = MODE_NONE;
  124. size_t numverifencs = 1;
  125. if (argc == 2 || argc == 3) {
  126. if (!strcmp(argv[1], "priv")) {
  127. mode = MODE_PRIV;
  128. } else if (!strcmp(argv[1], "pub")) {
  129. mode = MODE_PUB;
  130. } else if (!strcmp(argv[1], "const")) {
  131. mode = MODE_CONST;
  132. }
  133. if (argc == 3) {
  134. numverifencs = atoi(argv[2]);
  135. }
  136. }
  137. if (mode == MODE_NONE || numverifencs < 1) {
  138. cerr << "Usage: " << argv[0] << " mode n" << endl << endl;
  139. cerr << "Where mode is one of:" << endl;
  140. cerr << " priv: use private Ptable" << endl;
  141. cerr << " pub: use public Ptable" << endl;
  142. cerr << " const: use constant public key (no Ptable)" << endl << endl;
  143. cerr << "and where n is the number of verifencs in the circuit" << endl;
  144. exit(1);
  145. }
  146. // Initialize the curve parameters
  147. default_r1cs_gg_ppzksnark_pp::init_public_params();
  148. typedef libff::Fr<default_r1cs_gg_ppzksnark_pp> FieldT;
  149. // Create protoboard
  150. libff::start_profiling();
  151. cout << "Keypair" << endl;
  152. protoboard<FieldT> pb;
  153. pb_variable<FieldT> C1x[numverifencs], C1y[numverifencs];
  154. pb_variable<FieldT> C2x[numverifencs], C2y[numverifencs];
  155. pb_variable<FieldT> Kx[numverifencs], Ky[numverifencs];
  156. pb_variable<FieldT> Px[numverifencs], Py[numverifencs];
  157. pb_variable_array<FieldT> Ptable[numverifencs];
  158. pb_variable<FieldT> k[numverifencs], s[numverifencs], y[numverifencs];
  159. const size_t numbits = FieldT::num_bits;
  160. // Allocate variables
  161. // Public outputs:
  162. for (size_t i = 0; i < numverifencs; ++i) {
  163. // El Gamal encryption of k under public key P (or H if MODE_CONST)
  164. // C1 = r*G, C2 = r*P + M (where M=(256*k+s,y))
  165. C1x[i].allocate(pb, "C1x");
  166. C1y[i].allocate(pb, "C1y");
  167. C2x[i].allocate(pb, "C2x");
  168. C2y[i].allocate(pb, "C2y");
  169. // Public key corresponding to private key k
  170. // K = k*G
  171. Kx[i].allocate(pb, "Kx");
  172. Ky[i].allocate(pb, "Ky");
  173. // Public inputs:
  174. // The public key P (if not MODE_CONST)
  175. if (mode != MODE_CONST) {
  176. Px[i].allocate(pb, "Px");
  177. Py[i].allocate(pb, "Py");
  178. }
  179. }
  180. if (mode != MODE_CONST) {
  181. for (size_t i = 0; i < numverifencs; ++i) {
  182. // The Ptable might be public or private, according to the mode
  183. Ptable[i].allocate(pb, 2*numbits, "Ptable");
  184. }
  185. }
  186. for (size_t i = 0; i < numverifencs; ++i) {
  187. // Private inputs:
  188. // k is a 246-bit random number
  189. k[i].allocate(pb, "k");
  190. // s and y are such that M = (256*k+s,y) is a point on the curve
  191. s[i].allocate(pb, "s");
  192. y[i].allocate(pb, "y");
  193. }
  194. // This sets up the protoboard variables so that the first n of them
  195. // represent the public input and the rest is private input
  196. if (mode == MODE_PRIV) {
  197. pb.set_input_sizes(8*numverifencs);
  198. } else if (mode == MODE_PUB) {
  199. pb.set_input_sizes(8*numverifencs+2*numbits*numverifencs);
  200. } else if (mode == MODE_CONST) {
  201. pb.set_input_sizes(6*numverifencs);
  202. }
  203. // Initialize the gadgets
  204. vector<verified_encryption_gadget<FieldT> > vencs;
  205. for (size_t i = 0; i < numverifencs; ++i) {
  206. vencs.emplace_back(pb, mode, C1x[i], C1y[i], C2x[i], C2y[i], Kx[i], Ky[i], Px[i], Py[i], Ptable[i], k[i], s[i], y[i]);
  207. }
  208. for (auto&& gadget : vencs) {
  209. gadget.generate_r1cs_constraints();
  210. }
  211. const r1cs_constraint_system<FieldT> constraint_system = pb.get_constraint_system();
  212. const r1cs_gg_ppzksnark_keypair<default_r1cs_gg_ppzksnark_pp> keypair = r1cs_gg_ppzksnark_generator<default_r1cs_gg_ppzksnark_pp>(constraint_system);
  213. // Add witness values
  214. cout << "Prover" << endl;
  215. if (mode != MODE_CONST) {
  216. for (size_t i = 0; i < numverifencs; ++i) {
  217. // A variable base point P
  218. pb.val(Px[i]) = FieldT("1095194319010475832867263440470707690447963461907735667341232728633587089702");
  219. pb.val(Py[i]) = FieldT("9185463202887631101218413269806857706246311016297504828581985913021301344974");
  220. }
  221. }
  222. for (size_t i = 0; i < numverifencs; ++i) {
  223. pb.val(k[i]) = FieldT("31329510635628557928212225120518124937732397714111203844965919301557399521");
  224. pb.val(s[i]) = FieldT(1);
  225. pb.val(y[i]) = FieldT("4364798287654239504994818950156019747851405522689486598132350453516910863367");
  226. }
  227. for (auto&& gadget : vencs) {
  228. gadget.generate_r1cs_witness();
  229. }
  230. 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());
  231. cout << "Verifier" << endl;
  232. bool verified = r1cs_gg_ppzksnark_verifier_strong_IC<default_r1cs_gg_ppzksnark_pp>(keypair.vk, pb.primary_input(), proof);
  233. cout << "Number of R1CS constraints: " << constraint_system.num_constraints() << endl;
  234. cout << "Primary (public) input length: " << pb.primary_input().size() << endl;
  235. // cout << "Primary (public) input: " << pb.primary_input() << endl;
  236. cout << "Auxiliary (private) input length: " << pb.auxiliary_input().size() << endl;
  237. // cout << "Auxiliary (private) input: " << pb.auxiliary_input() << endl;
  238. cout << "Verification status: " << verified << endl;
  239. ofstream pkfile(string("pk_verifenc_") + argv[1]);
  240. pkfile << keypair.pk;
  241. pkfile.close();
  242. ofstream vkfile(string("vk_verifenc_") + argv[1]);
  243. vkfile << keypair.vk;
  244. vkfile.close();
  245. ofstream pffile(string("proof_verifenc_") + argv[1]);
  246. pffile << proof;
  247. pffile.close();
  248. return 0;
  249. }