Invalid `define.go` for complex Guard
Closed this issue · 5 comments
Minimal example:
(module test)
(defcolumns X (BYTE :array[0:1]))
(defconstraint test
(:guard (reduce + (for k [1:1] [BYTE k])))
(vanishes! X))
This produces the following define.go
:
package define
import (
_ "embed"
"github.com/consensys/zkevm-monorepo/prover/symbolic"
)
func ZkEVMDefine(build *Builder) {
//
// Corset-computed columns
//
test__BYTE_0 := build.RegisterCommit("test.BYTE_0", build.Settings.Traces.Test)
test__BYTE_1 := build.RegisterCommit("test.BYTE_1", build.Settings.Traces.Test)
test__X := build.RegisterCommit("test.X", build.Settings.Traces.Test)
...
build.GlobalConstraint("test.test", test__BYTE_1.AsVariable(),.Mul(test__X.AsVariable()))
}
Note the last line contains a syntax error: ... AsVariable(),.Mul( ...
So, the issue is with this section of code:
fn render_expression(cs: &ConstraintSet, e: &Node) -> String {
match e.e() {
...
Expression::List(constraints) => constraints
.iter()
.map(|e| render_expression(cs, e))
.map(|mut x| {
if let Some(true) = x.chars().last().map(|c| c != ',') {
x.push(',');
}
x
})
.collect::<Vec<_>>()
.join("\n"),
In essence, we have a List
with a single item which is causing the problem.
Q) Does it even make sense to be rendering a List
at this stage? I don't see how the above code would even work in the case of a list with more than one element?
UPDATE: Seems that this is only arising in the case of :guard
?
Ok, we can fix the above by a slight modification in generator::apply_form
which handles the case for unit lists differently from others. However, this actually doesn't address the problem which gave rose to this issue. Minimal case for that is actually:
(module test)
(defcolumns X (BYTE :array[0:2]))
(defconstraint test
(:guard (+ (for k [0:2] [BYTE k])))
(vanishes! X))
Does this seem syntactically malformed? Its curious that corset
doesn't report any problem with it.
UPDATE: in the body of a constraint, this has an effect (though not the desired one). For example, this:
(module test)
(defcolumns X (BYTE :array[0:2]))
(defconstraint test
()
(vanishes! (+ (for k [0:2] [BYTE k]))))
Generates three vanishing constraints:
build.GlobalConstraint("test.test#0", test__BYTE_0.AsVariable())
build.GlobalConstraint("test.test#1", test__BYTE_1.AsVariable())
build.GlobalConstraint("test.test#2", test__BYTE_2.AsVariable())
But, I suppose the problem is that, in the context of a guard I suppose this doesn't even make sense.
(+ (for k [0:2] [BYTE k]))
This should fail at the verification of the arguments to +
, that accepts multiple arguments, but not an argument that is a list.
In this case, the appropriate guard expression would be (reduce + (for k [0:2] [BYTE k]))
This should fail at the verification of the arguments to +, that accepts multiple arguments, but not an argument that is a list.
Yeah, that makes sense. I will look into doing that tomorrow :)
Ok, merged in fix for the minimal example at top of this issue (which uses a reduce
). Have opened #191 for case when reduce
omitted.