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.

276 lines
7.3 KiB

4 years ago
4 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. # Circom
  2. Circom is a language designed to write arithmetic circuits that can be used in zero-knowledge proofs.
  3. In particular, it is designed to work in [zksnarks JavaScript library](https://github.com/iden3/zksnark).
  4. ## Usage
  5. ### Circom Docs
  6. You can read the details of circom in [the documentation webpage](https://docs.circom.io/).
  7. ### Tutorial
  8. A good starting point [is this tutorial](https://github.com/iden3/circom/blob/master/TUTORIAL.md)
  9. Also this [video](https://www.youtube.com/watch?v=-9TJa1hVsKA) is a good starting point.
  10. ### First circuit
  11. Creation of a circuit. This is an example of a NAND door:
  12. ```
  13. template NAND() {
  14. signal private input a;
  15. signal input b;
  16. signal output out;
  17. out <== 1 - a*b;
  18. a*(a-1) === 0;
  19. b*(b-1) === 0;
  20. }
  21. component main = NAND();
  22. ```
  23. The language uses mainly JavaScript/C syntax together with 5 extra operators to define the following constraints:
  24. `<==` , `==>` : These two operators are used to connect signals and at the same time imply a constraint.
  25. As it is shown in the above example, a value is assigned to `out` and a constraint is also generated. The assigned value must be of the form a*b+c where a,b and c are linear combinations of the signals.
  26. `<--` , `-->` : These operators assign values to signals but do not generate any constraints. This allows to assign to a signal any value involving strange operations like shifts, divisions, modulo operations, etc. In general, these operators are used together with a `===` operator in order to force the constraint.
  27. `===` : This operator defines a constraint. The constraint must be simplificable to a constraint of the form `a*b+c=0`, where `a`, `b` and `c` are linear combinations of the signals.
  28. In the above example, both inputs are forced to be binary by adding the constraints `a*(a-1)===0` and `b*(b-1) === 0`.
  29. ### Compilation the circuit
  30. First of all, the compiler must be installed by typing:
  31. ```
  32. npm install -g circom
  33. ````
  34. The circuit is compiled with the following command:
  35. ```
  36. circom mycircuit.circom -o mycircuit.json
  37. ```
  38. The resulting output ( `mycircuit.json` ) can be used in the [zksnarks JavaScript library](https://github.com/iden3/zksnark).
  39. In this library one can do the trusted setup, create the proofs and verify them.
  40. ### Number to binary
  41. In many situations, one has to convert an input to its binary representation. Therefore, the circuits can be written this way:
  42. ```
  43. template Num2Bits(n) {
  44. signal input in;
  45. signal output out[n];
  46. var lc1=0;
  47. for (var i = 0; i<n; i++) {
  48. out[i] <-- (in >> i) & 1;
  49. out[i] * (out[i] -1 ) === 0;
  50. lc1 += out[i] * 2**i;
  51. }
  52. lc1 === in;
  53. }
  54. component main = Num2Bits(8)
  55. ```
  56. First of all, note that templates can have parameters. This allows to create libraries with templates that generate circuits in parametric ways. In this case, the circuit has an output of 8 signals, but one can easily instantiate any circuit with any number of outputs.
  57. The inputs and outputs are defined as arrays. The programm allows multidimensional arrays for signals and variables.
  58. Then, the values are assigned to each of the signals. In this case, the values are assigned without the constraint using the shift and & operators:
  59. `out[i] <-- (in >> i) & 1;`
  60. Afterwards, the constraints need to be defined. In this case, there is a big constraint of the form:
  61. ```
  62. in === out[0]*2**0 + out[1]*2**1 + out[2]*2**2 + ... + out[n-1]*2**(n-1)
  63. ```
  64. We do this by using a variable `lc1` and adding each signal multiplied by its coefficient.
  65. This variable does not hold a value at compilation time, but it holds a linear combination and it is used in the last constraint:
  66. ```
  67. lc1 === in;
  68. ```
  69. The last step is to force each output to be binary. This is done by adding the following constraint to each output:
  70. ```
  71. out[i] * (out[i] -1 ) === 0;
  72. ```
  73. ### A binary adder
  74. Let's now create a 32bits adder.
  75. This operation could be done directly by adding a simple constraint `out === in1 + in2`,
  76. but doing this the operation would not be module `2**32` but `r`, where `r`is the range of the elliptic curve. In the case of the zCash current implementation of zkSNARKs this number is typically some prime close to 2**253.
  77. So, the strategy we will follow will be to first convert a number to binary, then do the addition using the binary representation like in regular electronic circuits, and finally change it back to a number.
  78. To do this, we create 3 files: `bitify.circom`, `binsum.circom` and `sum_test.circom`.
  79. bitify.circom:
  80. ```
  81. template Num2Bits(n) {
  82. signal input in;
  83. signal output out[n];
  84. var lc1=0;
  85. for (var i = 0; i<n; i++) {
  86. out[i] <-- (in >> i) & 1;
  87. out[i] * (out[i] -1 ) === 0;
  88. lc1 += out[i] * 2**i;
  89. }
  90. lc1 === in;
  91. }
  92. template Bits2Num(n) {
  93. signal input in[n];
  94. signal output out;
  95. var lc1=0;
  96. for (var i = 0; i<n; i++) {
  97. lc1 += in[i] * 2**i;
  98. }
  99. lc1 ==> out;
  100. }
  101. ```
  102. binsum.circom
  103. ```
  104. /*
  105. Binary sum
  106. ==========
  107. This component creates a binary sum componet of ops operands and n bits each operand.
  108. e is number of carries and it depends on the number of operands in the input.
  109. Main Constraint:
  110. in[0][0] * 2^0 + in[0][1] * 2^1 + ..... + in[0][n-1] * 2^(n-1) +
  111. + in[1][0] * 2^0 + in[1][1] * 2^1 + ..... + in[1][n-1] * 2^(n-1) +
  112. + ..
  113. + in[ops-1][0] * 2^0 + in[ops-1][1] * 2^1 + ..... + in[ops-1][n-1] * 2^(n-1) +
  114. ===
  115. out[0] * 2^0 + out[1] * 2^1 + + out[n+e-1] *2(n+e-1)
  116. To waranty binary outputs:
  117. out[0] * (out[0] - 1) === 0
  118. out[1] * (out[0] - 1) === 0
  119. .
  120. .
  121. .
  122. out[n+e-1] * (out[n+e-1] - 1) === 0
  123. */
  124. /* This function calculates the number of extra bits in the output to do the full sum. */
  125. function nbits(a) {
  126. var n = 1;
  127. var r = 0;
  128. while (n-1<a) {
  129. r++;
  130. n *= 2;
  131. }
  132. return r;
  133. }
  134. template BinSum(n, ops) {
  135. var nout = nbits((2**n -1)*ops);
  136. signal input in[ops][n];
  137. signal output out[nout];
  138. var lin = 0;
  139. var lout = 0;
  140. var k;
  141. var j;
  142. for (k=0; k<n; k++) {
  143. for (j=0; j<ops; j++) {
  144. lin += in[j][k] * 2**k;
  145. }
  146. }
  147. for (k=0; k<nout; k++) {
  148. out[k] <-- (lin >> k) & 1;
  149. // Ensure out is binary
  150. out[k] * (out[k] - 1) === 0;
  151. lout += out[k] * 2**k;
  152. }
  153. // Ensure the sum
  154. lin === lout;
  155. }
  156. ```
  157. sumtest.circom:
  158. ```
  159. include "bitify.circom"
  160. include "binsum.circom"
  161. template Adder() {
  162. signal private input a;
  163. signal input b;
  164. signal output out;
  165. component n2ba = Num2Bits(32);
  166. component n2bb = Num2Bits(32);
  167. component sum = BinSum(32,2);
  168. component b2n = Bits2Num(32);
  169. n2ba.in <== a;
  170. n2bb.in <== b;
  171. for (var i=0; i<32; i++) {
  172. sum.in[0][i] <== n2ba.out[i];
  173. sum.in[1][i] <== n2bb.out[i];
  174. b2n.in[i] <== sum.out[i];
  175. }
  176. out <== b2n.out;
  177. }
  178. component main = Adder();
  179. ```
  180. In this example we have shown how to design a top-down circuit with many subcircuits and how to connect them together. One can also see that auxiliary functions to do specific computations can be created.
  181. ### More examples.
  182. You can find more examples in this library of basic circits [circomlib](https://github.com/iden3/circomlib)
  183. ## License
  184. Circom is part of the iden3 project copyright 2018 0KIMS association and published with GPL-3 license. Please check the COPYING file for more details.