Finalizing the border between snarky-rs and snarky-ml

Problem

  • It's way too hard to refactor all the top-level stuff (too much recursive modules and types, not enough organization)
  • And even if we manage to do it, it'll be a nightmare to refactor the OCaml side as it uses top-level stuff as well
  • Another problem is that we can't easily pass closures to the Rust side

Proposed solution

  • preserve more logic in the OCaml side
  • for example, Typ should continue to exist on the OCaml side (same philosophy as the JS side)
  • one way to avoid passing typ and closures is to move some of the logic to the ocaml side like so:
let exists typ ~checked ~compute = let cvars = match has_witness state with true -> (* we run our closure ourselves *) let as_prover_backup = get_as_prover state in set_as_prover state true; let val = compute state in set_as_prover state as_prover_backup; let (fields, aux) = typ.value_to_fields val in (* this will store the value in the witness + return the correct cvars *) compute_ocaml_witness state fields false -> (* this will allocated cvars and return them *) compute_ocaml state typ.size_in_field_elements in let aux = typ.constraint_system_auxiliary () in let var = typ.var_of_fields (cvars, aux) in if checked then typ.check state var; var

where we exported some Rust functions in OCaml:

val has_witness : state -> bool val get_as_prover : state -> bool val set_as_prover : state -> bool -> unit val compute_ocaml_witness : state -> field array -> cvar array val compute_ocaml : state -> int -> cvar array
  • it is not ideal, as if we change some internals of snarky-rs this might cause bugs on the snarky-ml side
  • but the js side has the same issue I believe
  • I think this is an acceptable border between the Rust and the OCaml
  • this still doesn't solve the fact that Typ relies on top-level Cvar

Solution for Typ

  • add a 'cvar type variable to typ
  • this way we remove reliance on top-level Cvar there
  • and typ can remain top-level as well (yeay! no large refactoring in Mina!)

Solution for Run_state

  • since we have to keep run state as a global (for the imperative API), we could also keep the as_prover stuff in OCaml as well (since it's not really useful in Rust)
  • I believe the JS side does similar things with their own way of knowing if you're running in a computation or not
  • so the OCaml could declare a state like this, at a minimum:
type run_state = { state: rust_state, as_prover: bool, }
  • but a number of top-level places rely on run_state
  • we can do the same as with cvar, we can add a 'run_state type variable to places that need it
  • so this is in addition to the 'cvar type variable we just discussed, and the 'field type variable that has always existed
  • I guess this makes sense, everything that will be instantiated through Rust has to be a type variable everywhere due to the two instantiations of snarky
  • annoying but I don't see another way

How to test that idea?

Select a repo