ecgadget.hpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. #include "libsnark_headers.hpp"
  2. using namespace libsnark;
  3. // There are two types of values:
  4. // _constants_ are values known at circuit generation time; they
  5. // are global constants known to everyone
  6. // _variables_ are values that change in each use of the circuit;
  7. // they have two subtypes:
  8. //
  9. // _public variables_ are values known to both the prover
  10. // and verifier but change in each use of the circuit
  11. // _private variables_ are values known only to the prover
  12. // and change in each use of the circuit
  13. // Double a constant EC point (inx,iny) to yield (outx,outy). The input
  14. // point must not be the point at infinity.
  15. template<typename FieldT>
  16. static void ec_double_point(FieldT &outx, FieldT &outy,
  17. const FieldT &inx, const FieldT &iny)
  18. {
  19. FieldT xsq = inx.squared();
  20. FieldT lambda = (xsq * 3 - 3) * (iny * 2).inverse();
  21. outx = lambda.squared() - inx * 2;
  22. outy = lambda * (inx - outx) - iny;
  23. }
  24. // Add constant EC points (inx, iny) and (addx, addy) to yield (outx, outy).
  25. // inx and addx must not be equal.
  26. template<typename FieldT>
  27. static void ec_add_points(FieldT &outx, FieldT &outy,
  28. const FieldT &inx, const FieldT &iny,
  29. const FieldT &addx, const FieldT &addy)
  30. {
  31. FieldT lambda = (addy - iny) * (addx - inx).inverse();
  32. outx = lambda.squared() - (addx + inx);
  33. outy = lambda * (inx - outx) - iny;
  34. }
  35. // Double the variable EC point (inx,iny) to yield (outx,outy). The
  36. // input point must not be the point at infinity.
  37. template<typename FieldT>
  38. class ec_double_gadget : public gadget<FieldT> {
  39. private:
  40. pb_variable<FieldT> lambda, inxsq;
  41. public:
  42. const pb_variable<FieldT> outx, outy, inx, iny;
  43. ec_double_gadget(protoboard<FieldT> &pb,
  44. const pb_variable<FieldT> &outx,
  45. const pb_variable<FieldT> &outy,
  46. const pb_linear_combination<FieldT> &inx,
  47. const pb_linear_combination<FieldT> &iny) :
  48. gadget<FieldT>(pb, "ec_double_gadget"), outx(outx), outy(outy),
  49. inx(inx), iny(iny)
  50. {
  51. // Allocate variables to protoboard
  52. // The strings (like "x") are only for debugging purposes
  53. lambda.allocate(this->pb, "lambda");
  54. inxsq.allocate(this->pb, "inxsq");
  55. }
  56. void generate_r1cs_constraints()
  57. {
  58. // inxsq = inx * inx
  59. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(inx, inx, inxsq));
  60. // 2 * iny * lambda = 3 * inxsq - 3 (a = -3 on our curve)
  61. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(2 * iny, lambda, 3 * inxsq - 3));
  62. // outx = lambda^2 - 2 * inx
  63. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(lambda, lambda, outx + 2 * inx));
  64. // outy = lambda * (inx - outx) - iny
  65. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(lambda, inx - outx, outy + iny));
  66. }
  67. void generate_r1cs_witness()
  68. {
  69. this->pb.val(inxsq) = this->pb.lc_val(inx) * this->pb.lc_val(inx);
  70. this->pb.val(lambda) = (this->pb.val(inxsq) * 3 - 3) * (this->pb.lc_val(iny) * 2).inverse();
  71. this->pb.val(outx) = this->pb.val(lambda).squared() - this->pb.lc_val(inx) * 2;
  72. this->pb.val(outy) = this->pb.val(lambda) * (this->pb.lc_val(inx) - this->pb.val(outx)) - this->pb.lc_val(iny);
  73. }
  74. };
  75. // Add the variable EC point (addx,addy) to the variable EC point
  76. // (inx,iny) to yield (outx,outy). The input point must not be the
  77. // point at infinity.
  78. template<typename FieldT>
  79. class ec_add_gadget : public gadget<FieldT> {
  80. private:
  81. pb_variable<FieldT> lambda;
  82. public:
  83. const pb_variable<FieldT> outx, outy;
  84. const pb_linear_combination<FieldT> inx, iny, addx, addy;
  85. ec_add_gadget(protoboard<FieldT> &pb,
  86. const pb_variable<FieldT> &outx,
  87. const pb_variable<FieldT> &outy,
  88. const pb_linear_combination<FieldT> &inx,
  89. const pb_linear_combination<FieldT> &iny,
  90. const pb_linear_combination<FieldT> &addx,
  91. const pb_linear_combination<FieldT> &addy) :
  92. gadget<FieldT>(pb, "ec_add_gadget"),
  93. outx(outx), outy(outy), inx(inx), iny(iny), addx(addx), addy(addy)
  94. {
  95. // Allocate variables to protoboard
  96. // The strings (like "x") are only for debugging purposes
  97. lambda.allocate(this->pb, "lambda");
  98. }
  99. void generate_r1cs_constraints()
  100. {
  101. // (addx - inx) * lambda = addy - iny
  102. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(addx - inx, lambda, addy - iny));
  103. // outx = lambda^2 - (addx + inx)
  104. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(lambda, lambda, outx + addx + inx));
  105. // outy = lambda * (inx - outx) - iny
  106. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(lambda, inx - outx, outy + iny));
  107. }
  108. void generate_r1cs_witness()
  109. {
  110. this->pb.val(lambda) = (this->pb.lc_val(addy) - this->pb.lc_val(iny)) * (this->pb.lc_val(addx) - this->pb.lc_val(inx)).inverse();
  111. this->pb.val(outx) = this->pb.val(lambda).squared() - (this->pb.lc_val(addx) + this->pb.lc_val(inx));
  112. this->pb.val(outy) = this->pb.val(lambda) * (this->pb.lc_val(inx) - this->pb.val(outx)) - this->pb.lc_val(iny);
  113. }
  114. };
  115. // Add the variable EC point P to the constant EC point (inx,iny) to
  116. // yield (outx,outy). The input point must not be the point at
  117. // infinity.
  118. template<typename FieldT>
  119. class ec_constant_add_gadget : public gadget<FieldT> {
  120. private:
  121. pb_variable<FieldT> lambda;
  122. public:
  123. const pb_variable<FieldT> outx, outy;
  124. const pb_linear_combination<FieldT> inx, iny;
  125. const FieldT Px, Py;
  126. ec_constant_add_gadget(protoboard<FieldT> &pb,
  127. const pb_variable<FieldT> &outx,
  128. const pb_variable<FieldT> &outy,
  129. const pb_linear_combination<FieldT> &inx,
  130. const pb_linear_combination<FieldT> &iny,
  131. const FieldT &Px, const FieldT &Py) :
  132. gadget<FieldT>(pb, "ec_constant_add_gadget"),
  133. outx(outx), outy(outy), inx(inx), iny(iny), Px(Px), Py(Py)
  134. {
  135. // Allocate variables to protoboard
  136. // The strings (like "x") are only for debugging purposes
  137. lambda.allocate(this->pb, "lambda");
  138. }
  139. void generate_r1cs_constraints()
  140. {
  141. // (Px - inx) * lambda = Py - iny
  142. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(Px - inx, lambda, Py - iny));
  143. // outx = lambda^2 - (Px + inx)
  144. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(lambda, lambda, outx + Px + inx));
  145. // outy = lambda * (inx - outx) - iny
  146. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(lambda, inx - outx, outy + iny));
  147. }
  148. void generate_r1cs_witness()
  149. {
  150. this->pb.val(lambda) = (Py - this->pb.lc_val(iny)) * (Px - this->pb.lc_val(inx)).inverse();
  151. this->pb.val(outx) = this->pb.val(lambda).squared() - (Px + this->pb.lc_val(inx));
  152. this->pb.val(outy) = this->pb.val(lambda) * (this->pb.lc_val(inx) - this->pb.val(outx)) - this->pb.lc_val(iny);
  153. }
  154. };
  155. // Add constant EC point P0 or the constant EC point P1 to the variable
  156. // EC point (inx,iny) to yield (outx,outy). The input point must not be
  157. // the point at infinity. The input bit which controls which addition
  158. // is done.
  159. template<typename FieldT>
  160. class ec_2_constant_add_gadget : public gadget<FieldT> {
  161. private:
  162. pb_variable<FieldT> sumx, sumy;
  163. pb_linear_combination<FieldT> addx, addy;
  164. std::vector<ec_add_gadget<FieldT> > adder;
  165. public:
  166. const pb_variable<FieldT> outx, outy;
  167. const pb_linear_combination<FieldT> inx, iny;
  168. const pb_variable<FieldT> which;
  169. const FieldT P0x, P0y, P1x, P1y;
  170. ec_2_constant_add_gadget(protoboard<FieldT> &pb,
  171. const pb_variable<FieldT> &outx,
  172. const pb_variable<FieldT> &outy,
  173. const pb_linear_combination<FieldT> &inx,
  174. const pb_linear_combination<FieldT> &iny,
  175. const pb_variable<FieldT> &which,
  176. const FieldT &P0x, const FieldT &P0y,
  177. const FieldT &P1x, const FieldT &P1y) :
  178. gadget<FieldT>(pb, "ec_2_constant_add_gadget"),
  179. outx(outx), outy(outy), inx(inx), iny(iny), which(which),
  180. P0x(P0x), P0y(P0y), P1x(P1x), P1y(P1y)
  181. {
  182. // Allocate variables to protoboard
  183. addx.assign(pb, which * (P1x-P0x) + P0x);
  184. addy.assign(pb, which * (P1y-P0y) + P0y);
  185. adder.emplace_back(this->pb, outx, outy, inx, iny, addx, addy);
  186. }
  187. void generate_r1cs_constraints()
  188. {
  189. adder[0].generate_r1cs_constraints();
  190. }
  191. void generate_r1cs_witness()
  192. {
  193. addx.evaluate(this->pb);
  194. addy.evaluate(this->pb);
  195. adder[0].generate_r1cs_witness();
  196. }
  197. };
  198. #if 0
  199. // Add nothing, or one of the constant EC points P1, P2, or P3 to the EC
  200. // point (inx,iny) to yield (outx,outy). The input point must not be
  201. // the point at infinity. The two input bits add1 and add2 control what
  202. // is added. Typically, P3 will equal P1+P2, in which case this gadget
  203. // does two conditional constant adds simultaneously in just 6 constraints.
  204. template<typename FieldT>
  205. class ec_add_P123_gadget : public gadget<FieldT> {
  206. private:
  207. pb_variable<FieldT> lambda, sumx, sumy, move;
  208. public:
  209. const pb_variable<FieldT> outx, outy;
  210. const pb_linear_combination<FieldT> inx, iny;
  211. const pb_variable<FieldT> add1, add2;
  212. const FieldT P1x, P1y, P2x, P2y, P3x, P3y;
  213. ec_add_P123_gadget(protoboard<FieldT> &pb,
  214. const pb_variable<FieldT> &outx,
  215. const pb_variable<FieldT> &outy,
  216. const pb_linear_combination<FieldT> &inx,
  217. const pb_linear_combination<FieldT> &iny,
  218. const pb_variable<FieldT> &add1,
  219. const pb_variable<FieldT> &add2,
  220. const FieldT &P1x, const FieldT &P1y,
  221. const FieldT &P2x, const FieldT &P2y,
  222. const FieldT &P3x, const FieldT &P3y) :
  223. gadget<FieldT>(pb, "ec_add_P123_gadget"),
  224. outx(outx), outy(outy), inx(inx), iny(iny), add1(add1), add2(add2),
  225. P1x(P1x), P1y(P1y), P2x(P2x), P2y(P2y), P3x(P3x), P3y(P3y)
  226. {
  227. // Allocate variables to protoboard
  228. // The strings (like "x") are only for debugging purposes
  229. lambda.allocate(this->pb, "lambda");
  230. sumx.allocate(this->pb, "sumx");
  231. sumy.allocate(this->pb, "sumy");
  232. move.allocate(this->pb, "move");
  233. }
  234. void generate_r1cs_constraints()
  235. {
  236. // Strategy: if add1 = add2 = 0, we compute some nonsense but throw
  237. // it away later. Otherwise, the coordinates of the point to add
  238. // are a _linear_ function of add1 and add2 (since P1, P2, and P3
  239. // are public constants)
  240. // In particular, the point to add is ( (P3x - P2x) * add1 + (P3x -
  241. // P1x) * add2 + (P1x + P2x - P3x), (P3y - P2y) * add1 + (P3y - P1y) *
  242. // add2 + (P1y + P2y - P3y))
  243. // (addx - inx) * lambda = addy - iny
  244. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>((P3x - P2x) * add1 + (P3x - P1x) * add2 + (P1x + P2x - P3x) - inx, lambda, (P3y - P2y) * add1 + (P3y - P1y) * add2 + (P1y + P2y - P3y) - iny));
  245. // sumx = lambda^2 - (addx + inx)
  246. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(lambda, lambda, sumx + (P3x - P2x) * add1 + (P3x - P1x) * add2 + (P1x + P2x - P3x) + inx));
  247. // sumy = lambda * (inx - sumx) - iny
  248. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(lambda, inx - sumx, sumy + iny));
  249. // Now we want to conditionally move the sum. We want that
  250. // outx = (add1 || add2) ? sumx : inx
  251. // outy = (add1 || add2) ? sumy : iny
  252. // so we compute move = add1 || add2, and then
  253. // outx = inx + (sumx - inx) * move
  254. // outy = iny + (sumy - iny) * move
  255. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(1 - add1, 1 - add2, 1 - move));
  256. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(sumx - inx, move, outx - inx));
  257. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(sumy - iny, move, outy - iny));
  258. }
  259. void generate_r1cs_witness()
  260. {
  261. FieldT addxval = (P3x - P2x) * this->pb.val(add1) + (P3x - P1x) * this->pb.val(add2) + (P1x + P2x - P3x);
  262. FieldT addyval = (P3y - P2y) * this->pb.val(add1) + (P3y - P1y) * this->pb.val(add2) + (P1y + P2y - P3y);
  263. this->pb.val(lambda) = (addyval - this->pb.lc_val(iny)) * (addxval - this->pb.lc_val(inx)).inverse();
  264. this->pb.val(sumx) = this->pb.val(lambda).squared() - (addxval + this->pb.lc_val(inx));
  265. this->pb.val(sumy) = this->pb.val(lambda) * (this->pb.lc_val(inx) - this->pb.val(sumx)) - this->pb.lc_val(iny);
  266. bool a1 = this->pb.val(add1) != FieldT(0);
  267. bool a2 = this->pb.val(add2) != FieldT(0);
  268. this->pb.val(move) = a1 || a2;
  269. this->pb.val(outx) = (a1 || a2) ? this->pb.val(sumx) : this->pb.lc_val(inx);
  270. this->pb.val(outy) = (a1 || a2) ? this->pb.val(sumy) : this->pb.lc_val(iny);
  271. }
  272. };
  273. #endif
  274. // Compute A + s*P as (outx, outy) for an accumulator A, a given
  275. // constant point P, and s given as a bit vector. The _caller_ is
  276. // responsible for proving that the elements of svec are bits. The
  277. // (constant) accumulator excess (AXS) will be updated; when all the
  278. // computations are complete, AXS should be subtracted from the
  279. // accumulator A.
  280. template<typename FieldT>
  281. class ec_constant_scalarmul_vec_gadget : public gadget<FieldT> {
  282. private:
  283. FieldT Cx, Cy;
  284. pb_variable_array<FieldT> accumx, accumy;
  285. std::vector<ec_2_constant_add_gadget<FieldT> > twoadders;
  286. public:
  287. const pb_variable<FieldT> outx, outy;
  288. const pb_variable<FieldT> Ax, Ay;
  289. const pb_variable_array<FieldT> svec;
  290. const FieldT Px, Py;
  291. // Strategy: We compute (as compile-time constants) (powers of 2)
  292. // times P. Based on each bit of s, we add one of the constant points
  293. // C or (2^i * P) + C to the accumulator, and regardless of s, add C
  294. // to the excess.
  295. ec_constant_scalarmul_vec_gadget(protoboard<FieldT> &pb,
  296. const pb_variable<FieldT> &outx,
  297. const pb_variable<FieldT> &outy,
  298. const pb_variable<FieldT> &Ax,
  299. const pb_variable<FieldT> &Ay,
  300. const pb_variable_array<FieldT> &svec,
  301. const FieldT &Px, const FieldT &Py,
  302. FieldT &AXSx, FieldT &AXSy) :
  303. gadget<FieldT>(pb, "ec_constant_scalarmul_vec_gadget"),
  304. // Precomputed coordinates of C
  305. Cx(2),
  306. Cy("4950745124018817972378217179409499695353526031437053848725554590521829916331"),
  307. outx(outx), outy(outy), Ax(Ax), Ay(Ay), svec(svec), Px(Px), Py(Py)
  308. {
  309. size_t numbits = svec.size();
  310. accumx.allocate(this->pb, numbits-1, "accumx");
  311. accumy.allocate(this->pb, numbits-1, "accumy");
  312. FieldT twoiPx = Px, twoiPy = Py;
  313. size_t i = 0;
  314. while(i < numbits) {
  315. // Invariant: twoiP = 2^i * P
  316. FieldT twoiPCx, twoiPCy;
  317. ec_add_points(twoiPCx, twoiPCy, twoiPx, twoiPy, Cx, Cy);
  318. twoadders.emplace_back(this->pb,
  319. (i == numbits-1 ? outx : accumx[i]),
  320. (i == numbits-1 ? outy : accumy[i]),
  321. (i == 0 ? Ax : accumx[i-1]),
  322. (i == 0 ? Ay : accumy[i-1]),
  323. svec[i], Cx, Cy, twoiPCx, twoiPCy);
  324. FieldT newtwoiPx, newtwoiPy, newAXSx, newAXSy;
  325. ec_double_point(newtwoiPx, newtwoiPy, twoiPx, twoiPy);
  326. twoiPx = newtwoiPx;
  327. twoiPy = newtwoiPy;
  328. i += 1;
  329. ec_add_points(newAXSx, newAXSy, AXSx, AXSy, Cx, Cy);
  330. AXSx = newAXSx;
  331. AXSy = newAXSy;
  332. }
  333. }
  334. void generate_r1cs_constraints()
  335. {
  336. for (auto&& gadget : twoadders) {
  337. gadget.generate_r1cs_constraints();
  338. }
  339. }
  340. void generate_r1cs_witness()
  341. {
  342. for (auto&& gadget : twoadders) {
  343. gadget.generate_r1cs_witness();
  344. }
  345. }
  346. };
  347. // Compute A + s*P as (outx, outy) for an accumulator A, a given
  348. // constant point P, and s given as a field element. The (constant)
  349. // accumulator excess (AXS) will be updated; when all the computations
  350. // are complete, AXS should be subtracted from the accumulator A.
  351. template<typename FieldT>
  352. class ec_constant_scalarmul_gadget : public gadget<FieldT> {
  353. private:
  354. pb_variable_array<FieldT> svec;
  355. std::vector<packing_gadget<FieldT> > packers;
  356. std::vector<ec_constant_scalarmul_vec_gadget<FieldT> > vecgadget;
  357. public:
  358. const pb_variable<FieldT> outx, outy;
  359. const pb_variable<FieldT> Ax, Ay;
  360. const pb_variable<FieldT> s;
  361. const FieldT Px, Py;
  362. ec_constant_scalarmul_gadget(protoboard<FieldT> &pb,
  363. const pb_variable<FieldT> &outx,
  364. const pb_variable<FieldT> &outy,
  365. const pb_variable<FieldT> &Ax,
  366. const pb_variable<FieldT> &Ay,
  367. const pb_variable<FieldT> &s,
  368. const FieldT &Px, const FieldT &Py,
  369. FieldT &AXSx, FieldT &AXSy) :
  370. gadget<FieldT>(pb, "ec_constant_scalarmul_gadget"),
  371. outx(outx), outy(outy), Ax(Ax), Ay(Ay), s(s), Px(Px), Py(Py)
  372. {
  373. // Allocate variables to protoboard
  374. // The strings (like "x") are only for debugging purposes
  375. size_t numbits = FieldT::num_bits;
  376. svec.allocate(this->pb, numbits, "svec");
  377. packers.emplace_back(this->pb, svec, s);
  378. vecgadget.emplace_back(this->pb, outx, outy, Ax, Ay, svec, Px, Py, AXSx, AXSy);
  379. }
  380. void generate_r1cs_constraints()
  381. {
  382. packers[0].generate_r1cs_constraints(true);
  383. vecgadget[0].generate_r1cs_constraints();
  384. }
  385. void generate_r1cs_witness()
  386. {
  387. packers[0].generate_r1cs_witness_from_packed();
  388. vecgadget[0].generate_r1cs_witness();
  389. }
  390. };
  391. // Compute a*G + b*H as (outx, outy), given a and b as field elements.
  392. template<typename FieldT>
  393. class ec_pedersen_gadget : public gadget<FieldT> {
  394. private:
  395. pb_variable<FieldT> accinx, acciny, accmidx, accmidy, accoutx, accouty;
  396. std::vector<ec_constant_scalarmul_gadget<FieldT> > mulgadgets;
  397. std::vector<ec_constant_add_gadget<FieldT> > addgadget;
  398. const FieldT Gx, Gy, Hx, Hy, Ax, Ay;
  399. public:
  400. const pb_variable<FieldT> outx, outy, a, b;
  401. ec_pedersen_gadget(protoboard<FieldT> &pb,
  402. const pb_variable<FieldT> &outx,
  403. const pb_variable<FieldT> &outy,
  404. const pb_variable<FieldT> &a,
  405. const pb_variable<FieldT> &b) :
  406. gadget<FieldT>(pb, "ec_pedersen_gadget"),
  407. outx(outx), outy(outy), a(a), b(b),
  408. // Precomputed coordinates of G, H, and A
  409. Gx(0),
  410. Gy("11977228949870389393715360594190192321220966033310912010610740966317727761886"),
  411. Hx(1),
  412. Hy("21803877843449984883423225223478944275188924769286999517937427649571474907279"),
  413. Ax("7536839002660211356286040193441766649532044555061394833845553337792579131020"),
  414. Ay("11391058648720923807988142436733355540810929560298907319389650598553246451302")
  415. {
  416. // Allocate variables to protoboard
  417. // The strings (like "x") are only for debugging purposes
  418. accinx.allocate(this->pb, "accinx");
  419. acciny.allocate(this->pb, "acciny");
  420. accmidx.allocate(this->pb, "accmidx");
  421. accmidy.allocate(this->pb, "accmidy");
  422. accoutx.allocate(this->pb, "accoutx");
  423. accouty.allocate(this->pb, "accouty");
  424. // Initialize the accumulator
  425. FieldT AXSx = Ax;
  426. FieldT AXSy = Ay;
  427. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(accinx, 1, Ax));
  428. this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(acciny, 1, Ay));
  429. // Initialize the gadgets
  430. mulgadgets.emplace_back(this->pb, accmidx, accmidy, accinx, acciny, a, Gx, Gy, AXSx, AXSy);
  431. mulgadgets.emplace_back(this->pb, accoutx, accouty, accmidx, accmidy, b, Hx, Hy, AXSx, AXSy);
  432. // Subtract the accumulator excess to get the result
  433. addgadget.emplace_back(this->pb, outx, outy, accoutx, accouty, AXSx, -AXSy);
  434. }
  435. void generate_r1cs_constraints()
  436. {
  437. this->pb.val(accinx) = Ax;
  438. this->pb.val(acciny) = Ay;
  439. mulgadgets[0].generate_r1cs_constraints();
  440. mulgadgets[1].generate_r1cs_constraints();
  441. addgadget[0].generate_r1cs_constraints();
  442. }
  443. void generate_r1cs_witness()
  444. {
  445. mulgadgets[0].generate_r1cs_witness();
  446. mulgadgets[1].generate_r1cs_witness();
  447. addgadget[0].generate_r1cs_witness();
  448. }
  449. };