-
Notifications
You must be signed in to change notification settings - Fork 128
Description
Allowing Cryptol programs to reference external functions, written in other languages, could have several benefits:
- It could allow users to write high-performance primitives to make the interpreter faster or so that it's unnecessary to rewrite existing libraries in Cryptol.
- It could allow Cryptol code compiled to software to reference existing interfaces.
- It could do similarly for Cryptol code compiled to hardware.
- It could allow use of special decision procedures within provers to efficiently handle constructs outside of standards like SMT-Lib.
It could be possible to do this with very little change to the language. The notion of a primitive in Cryptol, as it exists, is close to what we need. Ultimately, this construct currently means that any prover, interpreter, or compiler needs to know how to model, execute, or generate code for that function without (necessarily) having access to Cryptol source code for it.
Given that users can already declare primitives within any source file, the missing piece seems to be having a way to map primitives to external references. Some programming languages with foreign function interfaces have very flexible mechanisms allowing users to specify how external code is called, how parameters are passed, and so on. In the name of simplicity, it may be better (at least at first, potentially permanently) to simply state what the calling convention for external code should be.
If we do that, then the only remaining piece is a way for users to specify where an external symbol is located. For the four use cases listed above, here are some possibilities:
- Specify an external shared library file containing the symbol. Assume that the library has a symbol with the same name that has a type compatible with the calling convention we would use when generating C code in (2) below.
- Compile the Cryptol code to a software implementation that includes a call to a function with the same name as the primitive, using some specified calling convention. No extra user input is needed until the linking stage.
- Similar to (2).
- Translate the declared primitive to a symbol with the same name in the generated formula.
One potential issue here would be the accidental use of primitives. Currently, trying to :prove a formula that references a user-declared primitive that the symbolic backend doesn't know about yields an "unimplemented primitive" message. It might be less user-friendly to instead get an error back from the solver that it doesn't understand the formula Cryptol has sent it. Perhaps an additional marker, such as an external primitive or even just external could make this more explicit?
For case (1), one remaining issue is to tell the interpreter where to find the shared library containing the code to execute. We could follow Cryptol 1 by adding syntax to specify this within a Cryptol source file. Or we could allow the interpreter to read some sort of separate "map" file that tells it where to find primitives it doesn't have built-in support for.