Open RyanGlScott opened 1 week ago
@Isweet suggests that we could make this work by treating BaseBVRepr
and MirVectorRepr BoolRepr
as belonging to the same equivalence class, and when we try to equate one with the other, performing explicit conversions where necessary. I am somewhat on the fence about needing to sprinkle conversions in various places, since this feels like we are sidestepping a design issue to some extent, but that might be one way to unblock this.
@RyanGlScott, I suspect your intuition about how to work around this issue is better, so I'd recommend going with your gut rather than mine.
I'd only recommend documenting the purpose of each Crucible type (with some explanation of why they must be different).
We ultimately need #1976 anyway, I think.
Consider the following Rust function, which uses an array of
bool
s:You would expect that SAW would be able to verify
f
against the following specification:Surprisingly, however, it can't:
The reason this happens is rather unfortunate:
mir_fresh_var
does it take the supplied MIR type and convert it into its corresponding Cryptol type. In the case ofmir_fresh_var "a" (mir_array 8 mir_bool)
, the corresponding Cryptol type is[8]Bit
, i.e.,[8]
.mir_verify
, SAW needs to check that the type of the specification (spec
) matches the type of the original Rust function. It does so by (1) converting each Rust argument type in the function's type signature to its corresponding Crucible type, (2) converting each argument type passed tomir_execute_func
to its corresponding Crucible type, and (3) checking if the Crucible types match.MirVectorRepr
(see here), and the Crucible type corresponding tobool
isBoolRepr
(see here). Therefore, the full Crucible type correspoinding to[bool; 8]
isMirVectorRepr BoolRepr
.mir_execute_func [llvm_term a]
, and the type ofa
is[8]
. The Crucible type corresponding to[8]
isBaseBVRepr (knownNat @8)
: see here. (This is the same Crucible type that you'd get foru8
—more on this later.)MirVectorRepr BoolRepr
andBaseBVRepr (knownNat @8)
are not the same, yielding a type error. (The error message complains about[bool; 8]
andu8
, but these are basically just pretty-printed versions of the Crucible types.)The key step here is in picking a Crucible type for
[8]
. This choice is somewhat arbitrary, as we could just as well pickBaseBVRepr (knownNat @8)
orMirVectorRepr BoolRepr
. Picking the former is usually the more sensible option, as it happens to correspond to the same Crucible type that is assigned to types such asu8
(see here), and these integer types are far more common thatbool
arrays. Unfortunately, this choice comes at the expense of making it impossible to write SAW specifications like the one above.A handful of scattered observations:
Bit
s: they're both represented by the same type[8]
. In this sense, Cryptol's type system is more coarse-grained than Crucible's type system, which has separate types for these.BoolRepr
. The closest thing that LLVM has is thei1
type, but this is translated to the Cryptol type[1]
(a 1-bit word), notBit
. As such, the LLVM typesi8
and[8 x i1]
would be represented by entirely different Cryptol types ([8]
and[8][1]
, respectively).A workaround for this issue is to avoiding using
mir_fresh_var
. One way to do this is by creating fresh variables for each individual element of thebool
array rather than creating a single fresh variable for the entire array, which is what themir_fresh_expanded_value
command does. That is, SAW does successfully verify the following spec:Ultimately, I suspect that fixing this issue will require us to make SAW more flexible about how we embed types into Cryptol, as proposed in https://github.com/GaloisInc/saw-script/issues/1976. This is because the types
u8
and[bool; 8]
have the same representation in Cryptol, but different Crucible representations. Until then, themir_fresh_expanded_value
trick mentioned above is a serviceable workaround.Lastly, one radical idea: could we fix this issue by changing the Crucible representation of
bool
fromBoolRepr
toBaseBVRepr (knownNat @1)
, similarly to how LLVM'si1
type is handled? Perhaps so, but this would require changing a fair bit of code incrucible-mir
to accommodate this, and it's unclear to me whether that is a good idea. In any case, we want to fix https://github.com/GaloisInc/saw-script/issues/1976 anyway, so it's likely best to pursue a solution there.