You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

298 lines
8.4 KiB

5 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. /*
  2. Copyright 2018 0KIMS association.
  3. This file is part of circom (Zero Knowledge Circuit Compiler).
  4. circom is a free software: you can redistribute it and/or modify it
  5. under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. circom is distributed in the hope that it will be useful, but WITHOUT
  9. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  10. or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  11. License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with circom. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. include "mux3.circom";
  16. include "montgomery.circom";
  17. include "babyjub.circom";
  18. /*
  19. Window of 3 elements, it calculates
  20. out = base + base*in[0] + 2*base*in[1] + 4*base*in[2]
  21. out4 = 4*base
  22. The result should be compensated.
  23. */
  24. /*
  25. The scalar is s = a0 + a1*2^3 + a2*2^6 + ...... + a81*2^243
  26. First We calculate Q = B + 2^3*B + 2^6*B + ......... + 2^246*B
  27. Then we calculate S1 = 2*2^246*B + (1 + a0)*B + (2^3 + a1)*B + .....+ (2^243 + a81)*B
  28. And Finaly we compute the result: RES = SQ - Q
  29. As you can see the input of the adders cannot be equal nor zero, except for the last
  30. substraction that it's done in montgomery.
  31. A good way to see it is that the accumulator input of the adder >= 2^247*B and the other input
  32. is the output of the windows that it's going to be <= 2^246*B
  33. */
  34. template WindowMulFix() {
  35. signal input in[3];
  36. signal input base[2];
  37. signal output out[2];
  38. signal output out8[2]; // Returns 8*Base (To be linked)
  39. component mux = MultiMux3(2);
  40. mux.s[0] <== in[0];
  41. mux.s[1] <== in[1];
  42. mux.s[2] <== in[2];
  43. component dbl2 = MontgomeryDouble();
  44. component adr3 = MontgomeryAdd();
  45. component adr4 = MontgomeryAdd();
  46. component adr5 = MontgomeryAdd();
  47. component adr6 = MontgomeryAdd();
  48. component adr7 = MontgomeryAdd();
  49. component adr8 = MontgomeryAdd();
  50. // in[0] -> 1*BASE
  51. mux.c[0][0] <== base[0];
  52. mux.c[1][0] <== base[1];
  53. // in[1] -> 2*BASE
  54. dbl2.in[0] <== base[0];
  55. dbl2.in[1] <== base[1];
  56. mux.c[0][1] <== dbl2.out[0];
  57. mux.c[1][1] <== dbl2.out[1];
  58. // in[2] -> 3*BASE
  59. adr3.in1[0] <== base[0];
  60. adr3.in1[1] <== base[1];
  61. adr3.in2[0] <== dbl2.out[0];
  62. adr3.in2[1] <== dbl2.out[1];
  63. mux.c[0][2] <== adr3.out[0];
  64. mux.c[1][2] <== adr3.out[1];
  65. // in[3] -> 4*BASE
  66. adr4.in1[0] <== base[0];
  67. adr4.in1[1] <== base[1];
  68. adr4.in2[0] <== adr3.out[0];
  69. adr4.in2[1] <== adr3.out[1];
  70. mux.c[0][3] <== adr4.out[0];
  71. mux.c[1][3] <== adr4.out[1];
  72. // in[4] -> 5*BASE
  73. adr5.in1[0] <== base[0];
  74. adr5.in1[1] <== base[1];
  75. adr5.in2[0] <== adr4.out[0];
  76. adr5.in2[1] <== adr4.out[1];
  77. mux.c[0][4] <== adr5.out[0];
  78. mux.c[1][4] <== adr5.out[1];
  79. // in[5] -> 6*BASE
  80. adr6.in1[0] <== base[0];
  81. adr6.in1[1] <== base[1];
  82. adr6.in2[0] <== adr5.out[0];
  83. adr6.in2[1] <== adr5.out[1];
  84. mux.c[0][5] <== adr6.out[0];
  85. mux.c[1][5] <== adr6.out[1];
  86. // in[6] -> 7*BASE
  87. adr7.in1[0] <== base[0];
  88. adr7.in1[1] <== base[1];
  89. adr7.in2[0] <== adr6.out[0];
  90. adr7.in2[1] <== adr6.out[1];
  91. mux.c[0][6] <== adr7.out[0];
  92. mux.c[1][6] <== adr7.out[1];
  93. // in[7] -> 8*BASE
  94. adr8.in1[0] <== base[0];
  95. adr8.in1[1] <== base[1];
  96. adr8.in2[0] <== adr7.out[0];
  97. adr8.in2[1] <== adr7.out[1];
  98. mux.c[0][7] <== adr8.out[0];
  99. mux.c[1][7] <== adr8.out[1];
  100. out8[0] <== adr8.out[0];
  101. out8[1] <== adr8.out[1];
  102. out[0] <== mux.out[0];
  103. out[1] <== mux.out[1];
  104. }
  105. /*
  106. This component does a multiplication of a escalar times a fix base
  107. Signals:
  108. e: The scalar in bits
  109. base: the base point in edwards format
  110. out: The result
  111. dbl: Point in Edwards to be linked to the next segment.
  112. */
  113. template SegmentMulFix(nWindows) {
  114. signal input e[nWindows*3];
  115. signal input base[2];
  116. signal output out[2];
  117. signal output dbl[2];
  118. var i;
  119. var j;
  120. // Convert the base to montgomery
  121. component e2m = Edwards2Montgomery();
  122. e2m.in[0] <== base[0];
  123. e2m.in[1] <== base[1];
  124. component windows[nWindows];
  125. component adders[nWindows];
  126. component cadders[nWindows];
  127. // In the last step we add an extra doubler so that numbers do not match.
  128. component dblLast = MontgomeryDouble();
  129. for (i=0; i<nWindows; i++) {
  130. windows[i] = WindowMulFix();
  131. cadders[i] = MontgomeryAdd();
  132. if (i==0) {
  133. windows[i].base[0] <== e2m.out[0];
  134. windows[i].base[1] <== e2m.out[1];
  135. cadders[i].in1[0] <== e2m.out[0];
  136. cadders[i].in1[1] <== e2m.out[1];
  137. } else {
  138. windows[i].base[0] <== windows[i-1].out8[0];
  139. windows[i].base[1] <== windows[i-1].out8[1];
  140. cadders[i].in1[0] <== cadders[i-1].out[0];
  141. cadders[i].in1[1] <== cadders[i-1].out[1];
  142. }
  143. for (j=0; j<3; j++) {
  144. windows[i].in[j] <== e[3*i+j];
  145. }
  146. if (i<nWindows-1) {
  147. cadders[i].in2[0] <== windows[i].out8[0];
  148. cadders[i].in2[1] <== windows[i].out8[1];
  149. } else {
  150. dblLast.in[0] <== windows[i].out8[0];
  151. dblLast.in[1] <== windows[i].out8[1];
  152. cadders[i].in2[0] <== dblLast.out[0];
  153. cadders[i].in2[1] <== dblLast.out[1];
  154. }
  155. }
  156. for (i=0; i<nWindows; i++) {
  157. adders[i] = MontgomeryAdd();
  158. if (i==0) {
  159. adders[i].in1[0] <== dblLast.out[0];
  160. adders[i].in1[1] <== dblLast.out[1];
  161. } else {
  162. adders[i].in1[0] <== adders[i-1].out[0];
  163. adders[i].in1[1] <== adders[i-1].out[1];
  164. }
  165. adders[i].in2[0] <== windows[i].out[0];
  166. adders[i].in2[1] <== windows[i].out[1];
  167. }
  168. component m2e = Montgomery2Edwards();
  169. component cm2e = Montgomery2Edwards();
  170. m2e.in[0] <== adders[nWindows-1].out[0];
  171. m2e.in[1] <== adders[nWindows-1].out[1];
  172. cm2e.in[0] <== cadders[nWindows-1].out[0];
  173. cm2e.in[1] <== cadders[nWindows-1].out[1];
  174. component cAdd = BabyAdd();
  175. cAdd.x1 <== m2e.out[0];
  176. cAdd.y1 <== m2e.out[1];
  177. cAdd.x2 <== -cm2e.out[0];
  178. cAdd.y2 <== cm2e.out[1];
  179. cAdd.xout ==> out[0];
  180. cAdd.yout ==> out[1];
  181. windows[nWindows-1].out8[0] ==> dbl[0];
  182. windows[nWindows-1].out8[1] ==> dbl[1];
  183. }
  184. /*
  185. This component multiplies a escalar times a fixed point BASE (twisted edwards format)
  186. Signals
  187. e: The escalar in binary format
  188. out: The output point in twisted edwards
  189. */
  190. template EscalarMulFix(n, BASE) {
  191. signal input e[n]; // Input in binary format
  192. signal output out[2]; // Point (Twisted format)
  193. var nsegments = (n-1)\246 +1; // 249 probably would work. But I'm not sure and for security I keep 246
  194. var nlastsegment = n - (nsegments-1)*249;
  195. component segments[nsegments];
  196. component m2e[nsegments-1];
  197. component adders[nsegments-1];
  198. var s;
  199. var i;
  200. var nseg;
  201. var nWindows;
  202. for (s=0; s<nsegments; s++) {
  203. nseg = (s < nsegments-1) ? 249 : nlastsegment;
  204. nWindows = ((nseg - 1)\3)+1;
  205. segments[s] = SegmentMulFix(nWindows);
  206. for (i=0; i<nseg; i++) {
  207. segments[s].e[i] <== e[s*249+i];
  208. }
  209. for (i = nseg; i<nWindows*3; i++) {
  210. segments[s].e[i] <== 0;
  211. }
  212. if (s==0) {
  213. segments[s].base[0] <== BASE[0];
  214. segments[s].base[1] <== BASE[1];
  215. } else {
  216. m2e[s-1] = Montgomery2Edwards();
  217. adders[s-1] = BabyAdd();
  218. segments[s-1].dbl[0] ==> m2e[s-1].in[0];
  219. segments[s-1].dbl[1] ==> m2e[s-1].in[1];
  220. m2e[s-1].out[0] ==> segments[s].base[0];
  221. m2e[s-1].out[1] ==> segments[s].base[1];
  222. if (s==1) {
  223. segments[s-1].out[0] ==> adders[s-1].x1;
  224. segments[s-1].out[1] ==> adders[s-1].y1;
  225. } else {
  226. adders[s-2].xout ==> adders[s-1].x1;
  227. adders[s-2].yout ==> adders[s-1].y1;
  228. }
  229. segments[s].out[0] ==> adders[s-1].x2;
  230. segments[s].out[1] ==> adders[s-1].y2;
  231. }
  232. }
  233. if (nsegments == 1) {
  234. segments[0].out[0] ==> out[0];
  235. segments[0].out[1] ==> out[1];
  236. } else {
  237. adders[nsegments-2].xout ==> out[0];
  238. adders[nsegments-2].yout ==> out[1];
  239. }
  240. }