Skip to content

Scoping

Circom has static scoping like C and Rust. However, we have that signals, buses and components must have global scoping and hence they should be defined at the top-level block of the template that defines them or, since circom 2.1.5, inside (nested) if blocks, but only if conditions are known at compilation time.

pragma circom 2.1.5;

template Cubes (N) {
   //Declaration of signals.
   signal input in[N];
   signal output out[N];

   //Statements.
   for (var i = 0; i < N; i++) {
      signal aux;
      aux <== in[i]*in[i];
      out[i] <== aux*in[i];      
   }
}

component main = Cubes(5);

Signal aux cannot be declared in the block of the for instruction. The next compilation error is produced: "aux Is outside the initial scope".

Instead the following program compiles correctly.

pragma circom 2.1.5;
template A(n){
   signal input in;
   signal output outA;
   var i = 0;
   if(i < n){
    signal out <== 2;
    i = out;
   } 
   outA <== i;
}
component main = A(5);

since the condition i < n is known at compilation time, and then the declaration of signal out is allowed. However, if the condition was in < n, since it is not known at compilation time, it would output an error message because the declaration in that case is not allowed.

In any case, we apply a static scoping like in C++ or Rust, and a signal declared inside an if block is only visible inside the block it is declared.

Regarding visibility of signals of subcomponent, a signal x of component c is also visible in the template t that has declared c, using the notation c.x, if x is an input or and output of c. No access to intermediate signals of sub-components or signals of nested sub-components is allowed. For instance, if c is built using another component d, the signals of d cannot be accessed from t. This can be seen in the next code:

pragma circom 2.0.0;

template d(){
  signal output x;
  x <== 1;
}

template c(){
  signal output out2;
  out2 <== 2;
  component comp2 = d();
}

template t(){
  signal out;
  component c3 = c();
  out <== c3.comp2.x;
}

component main = t();

That rises and error on c3.comp2.x: "Signal not found in component: only accesses to input/output signals are allowed".

A var can be defined at any block and its visibility is reduced to the block like in C or Rust.