-
Notifications
You must be signed in to change notification settings - Fork 46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
generated circuit produces side-effects and wrong/impossible return value #59
Comments
I tested this example both with and without the switch to zk-SNARKs based on Groth's generic group construction; this does not have any influence on the result. |
Further AnalysisGenerated ConstraintsThese are the generated constraints in
analysing the constraintsBy calculating the values by hand from the above description, I was able to reproduce the same output value as in the issue description. As far as I can see, the problem is that two variable If they were boolean, the calculation would produce the correct result. conclusionfor some reason, the type of the characters (which should be
and results in illegal outputs. |
Thanks for the report and detailed analysis! I was able to reproduce the bug, and it does indeed seem to be a problem with the type annotations by the compiler. I'll take a look more closely soon and get back to you. |
Hi, any news? When do you expect to be able to have a closer look? |
Apologies for the delayed response. I looked into this a bit, but I haven't been able to find a root cause. It looks like this is bug that happens when passing structs with input-dependent indices to functions. The incorrect type annotations might be related, but you can see exactly where things are going wrong by adding some printf statements before and after the comparison in
which produces:
Clearly wrong, no matter what x and y are. I found two potential workarounds that produce the correct output:
Hardcoding the indices allows the compiler to do much more compile-time evaluation and makes the constraints much simpler (and correct, apparently). Maybe not so useful if you actually need a variable-length size, though.
This produces the expected output, even when called with input-dependent indices. This should be logically equivalent to your original program, so it might be good enough for your purposes. As for finding the root cause of the underlying bug, a good place to start is probably by comparing the spec files generated by your original code and the two workarounds. The spec files are generated by the frontend of the compiler (in The incorrect type annotations might be a clue; they are calculated here:
and used in |
Thank you very much, @maxhowald for your reply and apologies for my late reaction. when calling the line
#compute$$#compare_foo$$#compare_bars$$baz_a[0] and #compute$$#compare_foo$$#compare_bars$$baz_a[0] . Because they get assigned a constant value of 0, the type of the values is set to uint bits 1 . At this point, this is not an error. But we note that the lvalue #compute$$#compare_foo$$#compare_bars$$baz_a with the type uint bits 1 is stored in the variable table Function.vars .
The next step is then to do the actual initialization as specified in the code; assigning the value of The root cause of the compilation error In the aforementioned code, for each field in the array, the lvalue is retrieved via Fix
As far as i understand the problem, the above patch fixes the issue. I do not know if maybe there is another location in the code where the same problem occurs, you should have a look at that. The fix changes the type of the lvalue that has been created during the first initialisation of the variable. That undoes the optimization of the type. In my code example, this has no effect, as the value is overridden immediately; but it might have an effect if:
In that scenario (which i have not tested) the patch might also change the type hint in the variable table retroactively and undo type optimizations. Might cause some issues if the type has been set to be bigger than the declared type? (Wouldn't be legal C code, but seems to be the current handling of integer overflows in pequin) But other than for optimization, the type of an lvalue does not seem to have any effect on the computation anyway. I might be completely wrong here, though. |
For the last few days, I tried to understand how a code in the form
could return neither
22
nor0
, but instead values like-23881866888
. This seems to be some kind of side-effect from the two calls of foo, as the value changes depending on the number of calls tofoo
.I have not been able to find a good explanation for the issue. It seems to only appear if, in some way, the input is accessed and/or used.
This is the smallest example that I was able to find which still produces the effect. The input of the code is one
foo
which contains fourbars
. The code checks that the first and last twobars
, respectively, have the same value. It writes the result of the comparison inoutput->control
. The value should be either0
or22
, but nothing else. Instead, the value ofoutput->control
is-23881866888
. This should be impossible.example.c
example_v_inp_gen.h
example.outputs
The text was updated successfully, but these errors were encountered: