2.6. Signals and variables

Signals

The arithmetic circuits built with circom operate on signals, which contain field elements in Z/pZ. Signals can be named with an identifier or can be stored in arrays and are declared using the keyword signal as in the examples below.

signal input in;
signal input a;
signal s;
signal output out[n];

Types of signals

Signals can be defined as input or output, and are considered intermediate signals otherwise. In the previous piece of code, the variables in and a are input signals, the array out is an output and s is considered an intermediate signal. Note that we do not use any keyword for intermediate signals.

Private and public signals

Signals are always considered private. The programmer can distinguish between public and private signals only when defining the main component, by providing the list of public input signals.

template Main() {
signal private input a;
signal private input b;
signal public output out;
out <== a*b;
}

From the programmers point of view, only input and output signals are visible from outside the circuit, and hence no intermediate signal can be accessed.

Immutability of signals

Signals are immutable, which means that once they have a value assigned, this value cannot be changed later on. If a signal is assigned twice, a compilation error is generated (see Circom compiler).

At compilation time, the content of a signal is always considered unknown, even if a constant is already assigned to them (see Unknowns). The reason for that is to provide a precise (decidable) definition of which constructions are allowed and which are not, without depending on the power of the compiler to detect whether a signal has always a constant value or not.

Assignment to signals

Signals can only be assigned using the operators <-- or <== with the signal on the left hand side and and --> or ==> with the signal on the right hand side.

Safe assignments: <== ==>

These operators not only assign a value to a signal but also generate a constraint at the same time.

template Square() {
signal input in;
signal output out;
out <== in*in;
}

Computation assignments: <-- -->

When assigning a value to a signal using these operators, no constraint is generated. This means, that when compiling the circuit, there will be no condition reflecting how this assignment was done. Hence, using these operators is, in general, dangerous and should only be used when the assigned expression can not be included in a constraint.

signal input a;
signal inv;
inv <-- (a != 0) ? 1/a : 0;

In this example, the signal inv is the inverse of the input a (if a is different from 0). Note that it was not possible to assign the inverse to inv using <== , because the operation 1/a has not the form of a constraint (constant, linear or quadratic combinations of signals).

Using this kind of assignment should be combined with adding constraints with ===, which describe by means of constraint which are the assigned values.

In general, use the operators <== ==> to assign values to signals. If you use <-- -->, make sure there is a constraint === that captures that assignment.

Constraint assignments: ===

This operator allows to create an ad hoc constraint. In general, we will use === to reflect a calculation that was done using <-- --> or to impose a condition without an assignment.

For example, in the previous piece of code, we assigned to inva the inverse of the variable a, but there was no constraint capturing this fact. We can use === to ensure that inva is really the inverse of a.

signal input a;
signal inv;
inv <-- (a != 0) ? 1/a : 0;
a*inv === 1;

The following piece of code is a constraint that does not assign any value to a but imposes that it must be either 0 or 1 (a boolean).

a*(a-1) === 0;

Variables

Variables are identifiers that hold non signal data and are mutable.

Declaration of variables

Variables are declared using the keyword var and they hold either numerical values of the field or arithmetic expressions when they are used to build constraints. They can be named with a variable identifier or can be stored in arrays.

var x;

Assignment to variables

Variable assignment is made using the single equal symbol =. Declarations may also include an initialization, as in the following example.

var x;
x = 234456;
var y = 0;

An assignment is an statement and does not return any value, hence it cannot be part of an expression, which avoids misleading uses of =. Any use of = inside an expression leads to a compilation error.

The two examples below would result in a compilation error:

a = (b = 3) + 2;
var x;
if (x = 3){
var y = 0;
}