Open
Description
Description: Loop invariants are not optimized in Circom, leading to redundant constraints.
To reproduce this issue, create a file named circuit.circom
with the following content:
pragma circom 2.1.6;
template Module () {
signal input a;
signal input b;
signal output c;
var z;
for (var i = 0; i < 3; i++) {
z = a * b;
z === 12; // This constraint can be moved outside the loop
}
c <== z;
}
component main { public [ a ] } = Module();
/* INPUT = {
"a": "2",
"b": "6"
} */
Then compile and inspect the circuit:
circom --O2 --r1cs --sym --inspect circuit.circom
snarkjs r1cs print circuit.r1cs circuit.sym
You should see output similar to the following:
circom --O2 --r1cs --sym --inspect circuit.circom
template instances: 1
non-linear constraints: 4
linear constraints: 0
public inputs: 1
private inputs: 1
public outputs: 1
wires: 4
labels: 4
Written successfully: ./circuit.r1cs
Written successfully: ./circuit.sym
Everything went okay
snarkjs r1cs print circuit.r1cs circuit.sym
[INFO] snarkJS: [ main.a ] * [ main.b ] - [ 121 ] = 0
[INFO] snarkJS: [ main.a ] * [ main.b ] - [ 121 ] = 0
[INFO] snarkJS: [ main.a ] * [ main.b ] - [ 121 ] = 0
[INFO] snarkJS: [ 21888242871839275222246405745257275088548364400416034343698204186575808495616main.a ] * [ main.b ] - [ 21888242871839275222246405745257275088548364400416034343698204186575808495616main.c ] = 0
The [ main.a ] * [ main.b ] - [ 121 ] = 0
constraint is generated for each iteration of the loop, leading to repetitive constraints. This is inefficient and can be avoided by determining the value of z
outside the loop.