5.1. Circom compiler

Here you can find information about the work of the compiler and the messages you may get from it.

Compiler phases

Circom has two compilation phases:

  1. The construction phase, where the constraints are generated.

  2. The code generation phase, where the code to compute the witness is generated.

Unknowns

The concept of unknown is very important in the constructive part of circom, where constraints are generated. In order to understand the compiler behavior we need to define what is considered unknown at compile time:

  • The content of a signal is always considered unknown, and only constant values or template parameters are considered known.

  • A var whose value depends on unknowns is unknown.

  • Similarly, any expression that depends on unknowns is considered unknown.

  • Additionally, if an array is modified with an unknown expression in an unknown position then all positions of the array become unknown.

  • Finally, the result of a function call with unknown parameters is unknown.

The key point for the compiler in the constructive phase, is that the generation of constraints cannot depend on conditions (expressions) that are unknown.

Compiler messages

When running a circuit, you may get three kind of messages from the compiler.

Hint

The compiler throws a hint when there is part of the code that is allowed but uncommon, and hence, it is better to check if that part of the code was written that way on purpose.

For example, the compiler would detect that there is a single arrow in the following piece of code, which should be an operator uncommon to use.

template Function(n){
signal input in;
signal out;
out <-- in;
out === in;
}

It is easy to realize that the best option would be to gather lines 5 and 6 of the code into a single instruction using the double arrow: out <== in;.

Warning

The compiler throws a warning when there is part of the code that is allowed but it should not happen in general.

For example, the following template does not make use of the intermediate signal sig. Although allowed, the compiler would warn you that this signal is not written in any constraint.

template Function(n){
signal input in;
signal sig;
signal out;
out <== in;
}

Error

The compiler throws an error when there is part of the code that is not allowed.

For example, in the following piece of code, the double arrow instruction aux <== in*aux; would not be correct: remember that signals are immutable, so every round of the loop would imply a different condition for the aux signal. For instance, if in=2, we would first be imposing that aux = 2, then that aux = 4, later that aux = 8, et cetera, and all these constraints would be incompatible with each other.

template Exponentiation(n){
signal input in;
signal aux;
signal out;
aux <== 1;
for (var i = 0; i < n; i++){
aux <== in*aux;
}
out <== aux;
}