Closed rogermb closed 3 years ago
Hi,
Thanks for catching this problem and for helping with the minimal examples!
I traced the problem and found that line 618 in CircuitReader.cpp needs to be zeroPwires.push_back(make_shared<LinearCombination>(*l));
instead of zeroPwires.push_back(l);
.
I will push the fix later with other unrelated changes after verifying that it works, but so far, the problem seems to be in this line only. The problem appears in the patterns that you described, and when it happens, it leads to an observable error.
By the way, you mentioned that the code you provided works if the other line that sets resultPlusOne is used. I checked both cases, and both did not work before the fix. In the first case, the error is as you reported. In the second case, there is another exception. Both problems are fixed by changing the line that I mentioned above, but I am curious about the different behavior in the second case. Please confirm if it works completely fine under the same input before applying the suggested fix above.
Please confirm if it works completely fine under the same input before applying the suggested fix above.
I made the change to line 618 as you suggested, and everything works as it's supposed to now 🎉
I think I also found the reason why the first case (// Works
) worked on my machine - I was actually using a fork of libsnark that seems to contain a workaround for the first bug; and I completely missed that commit when I created this issue 😅
Thank you so much for your help!
Hi!
I recently ran into an issue when creating a circuit in which checkNonZero gets called on wires whose values themselves depend on the results of calls to checkNonZero. The jsnark circuit generation and evaulation work without any issues, but when libsnark gets called, it often fails with the error message
The constraint system is not satisifed by the value assignment - Terminating
.The strange part is that whether libsnark fails or not seems to depend on the execution order / order of operations in circuit.arith. For instance, in the minimal(-ish) example I've included below,
sumPrime.add(cPrime)
works just fine whilecPrime.add(sumPrime)
causes the aforementioned error in libsnark. If I replace calls to checkNonZero with a gadget that simply ORs all bit wires together, I'm also unable to reproduce the libsnark exception.I think the root cause of this issue is how NonZeroCheckBasicOp is implemented in CircuitReader.cpp. In
addNonzeroCheckConstraint
andmapValuesToProtoboard
, there seems to be an assumption that when the non-checkNonZero circuit inputs are set, all inputs of checkNonZero are present and can be used to compute the value of an auxiliary wire, which ultimately doesn't hold if the inputs of checkNonZero themselves depend on the outputs of other calls to checkNonZero.Given that NonZeroCheckBasicOp already has 2 output wires and the order of operations is correct inside jsnark, wouldn't it be possible to define the required auxiliary wire as a witness wire, assign its value in NonZeroCheckBasicOp.compute, and then just read in that value in libsnark? If you'd like, I could try to implement this in both jsnark and libsnark and create a pull request for both on your repos :smile:
Thank you very much for your work on this project!
Minimal example:
Output:
(edit:) The generated circuit file: