Zokrates / ZoKrates

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

Add syntactic sugar to make it easier to use `if` #721

Open qbzzt opened 3 years ago

qbzzt commented 3 years ago

In my Zokrates code the most common structure is:

foo = if <condition> then <something> else foo fi

I think this is common for other programmers too because we are used to imperative languages and this is very close to the imperative if statement.

Code will be more readable is we could use a simpler syntax for this structure, for example:

foo = if <condition> setto <something>

or even

if <condition> then foo=<something> (and throw a syntax error if after then you see something that isn't an assignment and there is no else)

Schaeff commented 3 years ago

I understand your concern however I do not find the alternatives you're proposing particularly readable, are they taken from another language?

On a related note, when it comes to conditionals in snarks, the main obstacle to conditional statements (and not just expressions like today) is that they can produce unexpected results for users, as both branches are always executed.

if condition { 
   assert(condition)
} else {
   assert(!condition)
}

This would always panic in a snark (unless panics are stored in variables, and only asserted together with the condition, which introduces an extra cost).

Note that the way we currently do things is not satisfactory as one could write the above today using function calls. One way to prevent that is to only allow identifiers in if/else statements: in that case the branches have to be computed explicitly before, and it's thus clear that both branches are executed. However I'm not sure this is great UX either.

qbzzt commented 3 years ago

How about this solution?

If the complier sees assert inside a conditional statement it:

  1. Outputs a warning that having assert inside a conditional causes inefficient code and is best avoided if possible.
  2. Have that panic stored in a variable so it can be checked along with the condition.

For functions, compile two versions, an "assured execution" version and a "conditional execution" version. Use the appropriate one based on whether the call is inside a condition or not.