Zokrates / ZoKrates

A toolbox for zkSNARKs on Ethereum
https://zokrates.github.io
GNU Lesser General Public License v3.0
1.8k stars 360 forks source link

The compiler panicked at 'called `Result::unwrap()` on an `Err` value: AssignmentMissing' #1351

Closed effectfully closed 9 months ago

effectfully commented 11 months ago

Environment

Steps to Reproduce

The following

def main(private field x) {
    field y = x == 0 ? 1 : 1/x;
    assert (y != 0);
    return;
}

being put in an internal_panic.zok file causes the prover to fail:


$ zokrates compile --isolate-branches --input internal_panic.zok
Compiling internal_panic.zok

Compiled code written to 'out'
Number of constraints: 10

$ zokrates setup -i out
Performing setup...
Verification key written to 'verification.key'
Proving key written to 'proving.key'
Setup completed

$ zokrates generate-proof -i out
Generating proof...
The compiler unexpectedly panicked
panicked at 'called `Result::unwrap()` on an `Err` value: AssignmentMissing', zokrates_ark/src/lib.rs:69:22
This is unexpected, please submit a full bug report at https://github.com/Zokrates/ZoKrates/issues
effectfully commented 11 months ago

Whoops, it looks like I forgot to call zokrates compute-witness -i out -a 0 and used some old witness file instead. With the setup phase everything seems to work properly:

$ zokrates compile --isolate-branches --input internal_panic.zok && zokrates setup -i out && zokrates compute-witness -i out -a 0 && zokrates generate-proof -i out
Compiling internal_panic.zok

Compiled code written to 'out'
Number of constraints: 10
Performing setup...
Verification key written to 'verification.key'
Proving key written to 'proving.key'
Setup completed
Computing witness...
Witness file written to 'witness'
Generating proof...
Proof written to 'proof.json'

Still, it's strange for a compiler to throw a panic instead of failing gracefully if it's a user error, so maybe that can be treated as a UX deficiency.

While I'm here, could you please point me to an explanation of how the original program

def main(private field x) {
    field y = x == 0 ? 1 : 1/x;
    assert (y != 0);
    return;
}

compiles? I've tried looking through the PR that added the isolate-branches feature, but failed to understand how 1/x compiles under a condition. I understand the c => (a == b) is !c || (a == b) part, but I fail to get how you handle 1/x under a condition. Or is there maybe a way for me to get some intermediate assembly that I could reverse-engineer myself?

effectfully commented 9 months ago

Got some help in the gitter and figure the rest myself, so closing the issue.