iden3 / circom

zkSnark circuit compiler
GNU General Public License v3.0
1.28k stars 244 forks source link

Signal indexed assignment fails in anonymous components #189

Closed BlakeMScurr closed 12 months ago

BlakeMScurr commented 1 year ago

I can't assign using <-- to an anonymous component if I'm indexing into the an array with a signal on the right hand side. We get the error: Non-quadratic constraint was detected statically, using unknown index will cause the constraint to be non-quadratic. But if I replace the anonymous component with a traditional component it works (i.e., uncomment the component below). I personally expect the semantics to be the same (i.e., I'm not trying to make a constraint, so this error shouldn't apply), and this pattern is showing up a lot in my circuits!

Demonstration circuit:

pragma circom 2.1.5;

template inner() {
    signal input a;
    a === 0;
}

template outer() {
    signal input array[2];
    signal input index;
    inner()(
        a <-- array[index]
    );
    // component m = inner();
    // m.a <-- array[index];
}

component main = outer();

Further, in a slightly different case, the non-quadratic constraint error appears to be suppressed and the compiler thinks that not inputs have been set. For this example we get Component mult_12_191 is created but not all its inputs are initialized.

pragma circom 2.1.5;

template mult(n) {
    signal input a[n];
    signal input b[n];
    0 === a[0] * b[0];
}

template outer(n) {
    signal input array[2][n];
    signal input index;
    mult(n)(
        a <-- array[index],
        b <-- array[index]
    );
    // component m = mult(n);
    // for (var i = 0; i < n; i++) {
    //     m.a[i] <-- array[index][i];
    //     m.b[i] <-- array[index][i];
    // }
}

component main = outer(5);
BlakeMScurr commented 1 year ago

Happy to help fix it as well, with a little direction!

alrubio commented 1 year ago

Hi @BlakeMScurr, thanks for reporting. Your program is not syntactically correct, but the provided error message is wrong. We will fix that. Regarding your program, you cannot use <-- when passing the parameters of the anonymous template (nor <==). You can only pass an expression in R1CS format (the expression can contain vars but altogether must be an expression in R1CS format). The reason is that the semantics of passing the argument in the anonymous component is an assignment with <== to the input of the component and this generates both an assignment in the witness generation code and a constraint in the constraint system. If you want to use <-- because the expression in not in R1CS format then you need to introduce a new intermediate signal say "aux" and give the value to "aux" with <-- and finally pass "aux" as parameter. But note that in this case the relation between "aux" and "array[index]" is not included in your constraints and hence in the circuit you have created. Therefore, whatever value given to "aux" will satisfy the constraints and this may create a security issue. Best, Albert

BlakeMScurr commented 1 year ago

Thanks for the reply Albert!

I'm a little confused about your answer, since the docs actually have an example of using <-- to pass an argument to an anonymous component, and I was able to compile it fine with circom 2.1.5:

template A(n){
   signal input a, b;
   signal output c;
   c <== a*b;
}
template B(n){
   signal input in[n];
   signal out <== A(n)( a <== in[0], b <-- in[1]);
}
component main = B(2);

Is this consistent with the idea that "the semantics of passing the argument in the anonymous component is an assignment with <== to the input of the component?" In this case, I thought b <-- in[1] would make an assignment in the witness generation code, but not create a constraint.

alrubio commented 1 year ago

Sorry for the confusion. The use of <-- described in the documentation was wrong we have remove it. On the other hand the use of names when passing parameter was not yet ready (although it was included in the docs, sorry). Thanks for pointing it out. We have now fixed the use of names but can only be used with <== Check it at the new release of circom 2.1.6

Although using <-- makes live easier we believe that it should be used only combined with adding constraints with === or calling other components that will add such constraints. Adding just a <-- array[index] adds no security at all on the values "a" can take, so an attacker can put any value in "a" and the proof will be verified.
Expressing that "a" is the signal at the position given by the signal "index" in the array of signals "array" can be costly in terms of constraints but is needed. A (relatively) simple way could be found in https://github.com/iden3/circomlib/blob/circom2.1/circuits/program_constructions/array_access.circom (you can remove the use of the tag {max}) This will be added soon to the new version of the circomlib. Thanks again for your help.