Open msaaltink opened 3 years ago
As you can probably tell, the goal_eval
/goal_eval_unint
commands are a bit unpolished. I originally implemented them as a quick hack to help in a particular proof I was working on, so it's useful to get some feedback from the experience of other people trying to use them for other things.
They work by round-tripping from saw-core to the what4 library and back: First, we evaluate the SAW term in the what4 backend, just like we'd do when sending a goal to a solver, but then we use the SAW backend of what4 to convert it back to a SAW term again. This works, but one of the limitations is that while Cryptol and SAW both have fixed-length sequence types, what4 does not. This means that an uninterpreted SAW/Cryptol function with a type like [4][32] -> [128]
needs to be encoded in what4 as a function of type [32] -> [32] -> [32] -> [32] -> [128]
; when it gets translated back to SAW its arguments are collected in a sequence. Similarly a variable x
of type [4][32]
needs to be expanded to four what4 variables each of type [32]
, which map back to the saw-core terms at 4 (Vec 32 Bool) x n
for n
= 0 to 3.
So how can we fix this? One easy thing to do would be to give goal_eval
a post-processing pass to turn terms like [at x 0, at x 1, at x 2, at x 3]
back into x
. However, conditionals would interfere, as you point out.
Another approach we could try is to use what4's primitive tuple/struct types. Currently we're not using them at all. But we could actually translate a variable with a type like [4][32]
into a single what4 variable of type ([32],[32],[32],[32])
; then we wouldn't have to do the same exploding/reassembling process we currently do that causes all the trouble. However, this might not be trivial to implement, because the saw-core evaluator is not really designed to work with backends that support vector types like this. I'll look into it, though.
About the presence of bitvector 32
: The saw-core function bitvector
is defined as bitvector n = Vec n Bool
, so for saw-core typechecking purposes, bitvector 32
and Vec 32 Bool
are interchangeable. However, for rewriting purposes they are distinct. Since it can cause problems for rewriting, I think maybe it's a good idea for us to completely remove the bitvector
type synonym from saw-core, and just use Vec n Bool
everywhere.
I have a fairly complex proof that will involve lots of rewriting, and am encountering some issues. Here's a stripped-down example illustrating one of them.
In the context of this Cryptol
we have the obvious fact
to_f (to_s x) == x
, but in my real example that fact is less obvious. So I want to prove it once, then apply it in proofs where needed. Here's what should be a simple proof: showf_s x == f x
. That's easy: unfoldf_s
andf
to getf1 (to_f (to_s (f2 x)) == f1 (f2 x)
, then apply the rewrite, and it is trivial. (Again, you need to imagine a more complex formula where the rewrite might apply several times over, and we really do not want to repeat the proof of the fact inline.)This plan fares poorly in SAW:
fails, and if we put in a
print_goal
command after the simplify step we seewhere the result of
to_s
has been split into 4 parts and then reassembled. Why?We can try to undo the splitting and reassembly with a rewrite. The naive attempt with
fails, and printing out the theorem shows that the pattern looks like
which will not match the formula we are trying to prove. Success can be obtained with this recipe (which Andrei was good enough to show me):
so that the proof script
works.
A few thoughts on this:
rejoin
ruleparse_core
is brittle; saw crashes if there are errors in the SAWCore string or if any of the many unsupported features appear.ite
has been pushed inside the sequence, so that therejoin
rule does not match, and it is difficult to find a work-around. SAW has also put the typebitvector 32
into the formula, which I cannot get from a Cryptol term, so I need to write very large SAWcore formulas to get rewrite rules that will match the terms that SAW creates.In summary, this seems much too complicated for what should be a very simple proof. Yes, in this case I can just unfold
to_f
andto_s
to get a proof, but in the real problem I am working on this is not a good option.