Closed atiselsts closed 1 week ago
Can u share an example , where the test passes ?
Let's say the input is [2, 2, 0]
. The expected output is 0 . An implementation that compares just the 2 first input signals, and outputs 1 on the example is going to pass your test set.
I wrote a more complete set of tests. Can make a PR if you agree.
const expectedOutput = 1;
witness = await circuit.calculateWitness({"a":[2,2,2]},true);
assert(Fr.eq(Fr.e(witness[0]), Fr.e(1)));
assert(Fr.eq(Fr.e(witness[1]), Fr.e(expectedOutput)));
const expectedOutput2 = 0;
witness = await circuit.calculateWitness({"a":[1,0,1]},true);
assert(Fr.eq(Fr.e(witness[0]), Fr.e(1)));
assert(Fr.eq(Fr.e(witness[1]), Fr.e(expectedOutput2)));
const expectedOutput3 = 0;
witness = await circuit.calculateWitness({"a":[3,3,0]},true);
assert(Fr.eq(Fr.e(witness[0]), Fr.e(1)));
assert(Fr.eq(Fr.e(witness[1]), Fr.e(expectedOutput3)));
const expectedOutput4 = 1;
witness = await circuit.calculateWitness({"a":[0,0,0]},true);
assert(Fr.eq(Fr.e(witness[0]), Fr.e(1)));
assert(Fr.eq(Fr.e(witness[1]), Fr.e(expectedOutput4)));
const expectedOutput5 = 0;
witness = await circuit.calculateWitness({"a":[1,2,2]},true);
assert(Fr.eq(Fr.e(witness[0]), Fr.e(1)));
assert(Fr.eq(Fr.e(witness[1]), Fr.e(expectedOutput5)));
const expectedOutput6 = 0;
witness = await circuit.calculateWitness({"a":[0,1,2]},true);
assert(Fr.eq(Fr.e(witness[0]), Fr.e(1)));
assert(Fr.eq(Fr.e(witness[1]), Fr.e(expectedOutput5)));
I have created PR25 to resolve this issue which I also encountered.
Which the current Equality test suite, the following Circuit which only checks the first 2 elements passes all the tests:
pragma circom 2.1.4;
template IsZero() {
signal input in;
signal output out;
signal inv;
inv <-- in!=0 ? 1/in : 0;
out <== -in*inv +1;
in*out === 0;
}
template IsEqual() {
signal input in[2];
signal output out;
component isz = IsZero();
in[1] - in[0] ==> isz.in;
isz.out ==> out;
}
template Equality() {
signal input a[3];
signal output c; // 1 Equal, 0 False
// a[0] == a[1] ?
component check1 = IsEqual();
check1.in[0] <== a[0];
check1.in[1] <== a[1];
c <== check1.out;
}
However this test will fail once we add in the additional 2 test cases:
witness = await circuit.calculateWitness({"a":[1,1,0]},true);
let expectedOutput3 = 0;
assert(Fr.eq(Fr.e(witness[0]), Fr.e(1)));
assert(Fr.eq(Fr.e(witness[1]), Fr.e(expectedOutput3)));
witness = await circuit.calculateWitness({"a":[2,1,1]},true);
let expectedOutput4 = 0;
assert(Fr.eq(Fr.e(witness[0]), Fr.e(1)));
assert(Fr.eq(Fr.e(witness[1]), Fr.e(expectedOutput4)));
A Circuit which correctly passes the expanded test suite must check all 3 values; one valid implementation:
pragma circom 2.1.4;
template IsZero() {
signal input in;
signal output out;
signal inv;
inv <-- in!=0 ? 1/in : 0;
out <== -in*inv +1;
in*out === 0;
}
template IsEqual() {
signal input in[2];
signal output out;
component isz = IsZero();
in[1] - in[0] ==> isz.in;
isz.out ==> out;
}
// Input 3 values using 'a'(array of length 3) and check if they all are equal.
// Return using signal 'c'.
template Equality() {
signal input a[3];
signal output c; // 1 Equal, 0 False
// a[0] == a[1] ?
component check1 = IsEqual();
check1.in[0] <== a[0];
check1.in[1] <== a[1];
// a[1] == a[2] ?
component check2 = IsEqual();
check2.in[0] <== a[1];
check2.in[1] <== a[2];
// constraint inspired by
// https://github.com/iden3/circomlib/blob/master/circuits/gates.circom#L29-L35
//
// a[0] == a[1] && a[1] == a[2]
c <== check1.out * check2.out;
}
component main = Equality();
Merged PR #26 already addressed this issue
The tests in
Equality.js
are very limited, just two test cases. I built a circuit that checks just the first 2 inputsa[0]
anda[1]
for equality, and was surprised to see that it passed these tests.I suggest adding more test cases such as [2, 2, 0] in the input.