When testing circuits written with Plonky2, one might want to see what happens when invalid witnesses are used. Unfortunately, it is very easy to trigger panics when this kind of tests is performed.
As far as I can tell, the culprit is an assert_eq! in the implementation of plonky2::iop::witness::WitnessWrite for plonky2::iop::witness::PartitionWitness.
The panic from that assert_eq! is triggered by the witness generation process in plonky2::iop::generator::generate_partial_witness.
It would be nice if the process didn't panic, and as far as I could see, an error propagation mechanism would be feasible, if one allowed changes in the signature of WitnessWrite::set_target so that the function returns a Result.
The obvious downside of this solution is that it would technically be a breaking change that affects all downstream crates that implement generators, given that calls <plonky2::iop::generator::GeneratedValues as WitnessWrite>::set_target are required for the implementation.
I say technically a breaking change because, since WitnessWrite::set_target currently returns (), there is no real reason to feed its output into the computation of other expressions, and therefore most downstream dependencies would only notice a bunch of new warnings on their code base. Still, that would be a breaking change and I am in no position to evaluate if it is beneficial.
In the meantime I had an idea to circumvent the problem in test environment. It's more of a hack than anything, but it seems to work.
The idea is to implement a super simple gate that only imposes the constraint
vars.local_wires[0] - vars.local_wires[1]
so that it is in a way logically equivalent to CircuitBuilder::connect.
This gate does not implement any generators, so that the assert_eq! that causes the panic is not called.
One can use that gate in tests instead of connect, so that the proof generator generates invalid proofs instead of raising panics.
Does it make sense as a workaround? If not, why?
Here follows my implementation of the gate in question. If the idea sketched above does not make sense, please ignore it. If it makes sense, is it implemented correctly?
When testing circuits written with Plonky2, one might want to see what happens when invalid witnesses are used. Unfortunately, it is very easy to trigger panics when this kind of tests is performed.
As far as I can tell, the culprit is an
assert_eq!
in the implementation ofplonky2::iop::witness::WitnessWrite
forplonky2::iop::witness::PartitionWitness
.The panic from that
assert_eq!
is triggered by the witness generation process inplonky2::iop::generator::generate_partial_witness
.It would be nice if the process didn't panic, and as far as I could see, an error propagation mechanism would be feasible, if one allowed changes in the signature of
WitnessWrite::set_target
so that the function returns aResult
.The obvious downside of this solution is that it would technically be a breaking change that affects all downstream crates that implement generators, given that calls
<plonky2::iop::generator::GeneratedValues as WitnessWrite>::set_target
are required for the implementation.I say technically a breaking change because, since
WitnessWrite::set_target
currently returns()
, there is no real reason to feed its output into the computation of other expressions, and therefore most downstream dependencies would only notice a bunch of new warnings on their code base. Still, that would be a breaking change and I am in no position to evaluate if it is beneficial.In the meantime I had an idea to circumvent the problem in test environment. It's more of a hack than anything, but it seems to work.
The idea is to implement a super simple gate that only imposes the constraint
vars.local_wires[0] - vars.local_wires[1]
so that it is in a way logically equivalent toCircuitBuilder::connect
. This gate does not implement any generators, so that theassert_eq!
that causes the panic is not called. One can use that gate in tests instead ofconnect
, so that the proof generator generates invalid proofs instead of raising panics.Does it make sense as a workaround? If not, why?
Here follows my implementation of the gate in question. If the idea sketched above does not make sense, please ignore it. If it makes sense, is it implemented correctly?