From 3ec0fa92c03fa9064f5d49cc05d01a3f4ef687ea Mon Sep 17 00:00:00 2001 From: Victor Dumitrescu Date: Wed, 11 Sep 2024 18:54:13 +0200 Subject: [PATCH] RISC-V PVM: OCaml API for proofs --- src/lib_riscv/pvm/backend.ml | 14 +++- src/lib_riscv/pvm/backend.mli | 14 +++- .../lib_sc_rollup_node/riscv_pvm.ml | 65 ++++++++++++++++--- src/riscv/lib/octez_riscv_api.ml | 6 ++ src/riscv/lib/octez_riscv_api.mli | 6 ++ src/riscv/lib/src/ocaml_api.rs | 43 ++++++++++++ 6 files changed, 135 insertions(+), 13 deletions(-) diff --git a/src/lib_riscv/pvm/backend.ml b/src/lib_riscv/pvm/backend.ml index 414f5b7aeffc..260fd2a85f2e 100644 --- a/src/lib_riscv/pvm/backend.ml +++ b/src/lib_riscv/pvm/backend.ml @@ -12,8 +12,6 @@ type reveals = unit type write_debug = string -> unit Lwt.t -type input_info - type state = Storage.State.t type status = Api.status @@ -22,6 +20,10 @@ type reveal_data = Api.reveal_data type input = Api.input +type input_request = Octez_riscv_api.input_request + +type proof = Octez_riscv_api.proof + (* The kernel debug logging function (`string -> unit Lwt.t`) passed by the node * to [compute_step] and [compute_step_many] cannot be passed directly * to the Rust backend, which expects a `u8 -> ()` function and cannot run Lwt @@ -73,3 +75,11 @@ let get_current_level state = Lwt.return (Api.octez_riscv_get_level state) let state_hash state = Api.octez_riscv_state_hash state let set_input state input = Lwt.return (Api.octez_riscv_set_input state input) + +let proof_start_state proof = Api.octez_riscv_proof_start_state proof + +let proof_stop_state proof = Api.octez_riscv_proof_stop_state proof + +let verify_proof input proof = Api.octez_riscv_verify_proof input proof + +let produce_proof input state = Api.octez_riscv_produce_proof input state diff --git a/src/lib_riscv/pvm/backend.mli b/src/lib_riscv/pvm/backend.mli index 491aa758a785..35512a29d629 100644 --- a/src/lib_riscv/pvm/backend.mli +++ b/src/lib_riscv/pvm/backend.mli @@ -10,8 +10,6 @@ type reveals type write_debug = string -> unit Lwt.t -type input_info - type state = Storage.State.t type status = Octez_riscv_api.status @@ -20,6 +18,10 @@ type reveal_data = Octez_riscv_api.reveal_data type input = Octez_riscv_api.input +type input_request = Octez_riscv_api.input_request + +type proof = Octez_riscv_api.proof + val compute_step_many : ?reveal_builtins:reveals -> ?write_debug:write_debug -> @@ -47,3 +49,11 @@ val get_current_level : state -> int32 option Lwt.t val state_hash : state -> bytes val set_input : state -> input -> state Lwt.t + +val proof_start_state : proof -> bytes + +val proof_stop_state : proof -> bytes + +val verify_proof : input option -> proof -> input_request option + +val produce_proof : input option -> state -> proof option diff --git a/src/proto_alpha/lib_sc_rollup_node/riscv_pvm.ml b/src/proto_alpha/lib_sc_rollup_node/riscv_pvm.ml index aced8941e598..5c8d71f4b43a 100644 --- a/src/proto_alpha/lib_sc_rollup_node/riscv_pvm.ml +++ b/src/proto_alpha/lib_sc_rollup_node/riscv_pvm.ml @@ -6,6 +6,34 @@ (* *) (*****************************************************************************) +type Environment.Error_monad.error += Riscv_proof_verification_failed + +type Environment.Error_monad.error += Riscv_proof_production_failed + +let () = + let open Environment.Error_monad in + let open Data_encoding in + let msg = "Proof verification failed" in + register_error_kind + `Permanent + ~id:"smart_rollup_riscv_proof_verification_failed" + ~title:msg + ~pp:(fun fmt () -> Format.fprintf fmt "%s" msg) + ~description:msg + unit + (function Riscv_proof_verification_failed -> Some () | _ -> None) + (fun () -> Riscv_proof_verification_failed) ; + let msg = "Proof production failed" in + register_error_kind + `Permanent + ~id:"smart_rollup_riscv_proof_production_failed" + ~title:msg + ~pp:(fun fmt () -> Format.fprintf fmt "%s" msg) + ~description:msg + unit + (function Riscv_proof_production_failed -> Some () | _ -> None) + (fun () -> Riscv_proof_production_failed) + open Protocol open Alpha_context module Context = Riscv_context @@ -44,13 +72,20 @@ module PVM : type hash = Sc_rollup.State_hash.t - type proof = void + type proof = Backend.proof - let proof_encoding = void + let proof_encoding = + Data_encoding.( + conv_with_guard + (function (_ : proof) -> ()) + (fun _ -> Error "proofs not implemented") + unit) - let proof_start_state = function (_ : proof) -> . + let proof_start_state proof = + Sc_rollup.State_hash.of_bytes_exn (Backend.proof_start_state proof) - let proof_stop_state = function (_ : proof) -> . + let proof_stop_state proof = + Sc_rollup.State_hash.of_bytes_exn (Backend.proof_stop_state proof) let state_hash state = Lwt.return (Sc_rollup.State_hash.of_bytes_exn (Backend.state_hash state)) @@ -91,23 +126,35 @@ module PVM : | Sc_rollup.(Reveal (Raw_data data)) -> Reveal (RawData data) | _ -> assert false + let of_pvm_input_request (_input_request : Backend.input_request) : + Sc_rollup.input_request = + raise (Invalid_argument "input_request not implemented") + let set_input input state = Backend.set_input state (to_pvm_input input) let eval state = Backend.compute_step state - let verify_proof ~is_reveal_enabled:_ _input = function (_ : proof) -> . + let verify_proof ~is_reveal_enabled:_ input_given proof = + let open Environment.Error_monad.Lwt_result_syntax in + match Backend.verify_proof (Option.map to_pvm_input input_given) proof with + | None -> tzfail Riscv_proof_verification_failed + | Some request -> return (of_pvm_input_request request) - let produce_proof _context ~is_reveal_enabled:_ _state _step = assert false + let produce_proof _context ~is_reveal_enabled:_ input_given state = + let open Environment.Error_monad.Lwt_result_syntax in + match Backend.produce_proof (Option.map to_pvm_input input_given) state with + | None -> tzfail Riscv_proof_production_failed + | Some proof -> return proof type output_proof = void let output_proof_encoding = void - let output_of_output_proof = function (_ : proof) -> . + let output_of_output_proof = function (_ : output_proof) -> . - let state_of_output_proof = function (_ : proof) -> . + let state_of_output_proof = function (_ : output_proof) -> . - let verify_output_proof = function (_ : proof) -> . + let verify_output_proof = function (_ : output_proof) -> . let produce_output_proof _context _state _output = assert false diff --git a/src/riscv/lib/octez_riscv_api.ml b/src/riscv/lib/octez_riscv_api.ml index 1a25ac9e5a61..7ad6660949bb 100644 --- a/src/riscv/lib/octez_riscv_api.ml +++ b/src/riscv/lib/octez_riscv_api.ml @@ -10,6 +10,8 @@ type id type status = Evaluating | WaitingForInput | WaitingForMetadata type reveal_data = RawData of string | Metadata of bytes * int32 type input = InboxMessage of int32 * int64 * string | Reveal of reveal_data +type input_request +type proof external octez_riscv_id_unsafe_of_raw_bytes: bytes -> id = "octez_riscv_id_unsafe_of_raw_bytes" external octez_riscv_storage_id_to_raw_bytes: id -> bytes = "octez_riscv_storage_id_to_raw_bytes" external octez_riscv_storage_id_equal: id -> id -> bool = "octez_riscv_storage_id_equal" @@ -32,3 +34,7 @@ external octez_riscv_state_hash: state -> bytes = "octez_riscv_state_hash" external octez_riscv_set_input: state -> input -> state = "octez_riscv_set_input" external octez_riscv_get_message_counter: state -> int64 = "octez_riscv_get_message_counter" external octez_riscv_storage_export_snapshot: repo -> id -> string -> (unit, [`Msg of string]) result = "octez_riscv_storage_export_snapshot" +external octez_riscv_proof_start_state: proof -> bytes = "octez_riscv_proof_start_state" +external octez_riscv_proof_stop_state: proof -> bytes = "octez_riscv_proof_stop_state" +external octez_riscv_verify_proof: input option -> proof -> input_request option = "octez_riscv_verify_proof" +external octez_riscv_produce_proof: input option -> state -> proof option = "octez_riscv_produce_proof" diff --git a/src/riscv/lib/octez_riscv_api.mli b/src/riscv/lib/octez_riscv_api.mli index 1a25ac9e5a61..7ad6660949bb 100644 --- a/src/riscv/lib/octez_riscv_api.mli +++ b/src/riscv/lib/octez_riscv_api.mli @@ -10,6 +10,8 @@ type id type status = Evaluating | WaitingForInput | WaitingForMetadata type reveal_data = RawData of string | Metadata of bytes * int32 type input = InboxMessage of int32 * int64 * string | Reveal of reveal_data +type input_request +type proof external octez_riscv_id_unsafe_of_raw_bytes: bytes -> id = "octez_riscv_id_unsafe_of_raw_bytes" external octez_riscv_storage_id_to_raw_bytes: id -> bytes = "octez_riscv_storage_id_to_raw_bytes" external octez_riscv_storage_id_equal: id -> id -> bool = "octez_riscv_storage_id_equal" @@ -32,3 +34,7 @@ external octez_riscv_state_hash: state -> bytes = "octez_riscv_state_hash" external octez_riscv_set_input: state -> input -> state = "octez_riscv_set_input" external octez_riscv_get_message_counter: state -> int64 = "octez_riscv_get_message_counter" external octez_riscv_storage_export_snapshot: repo -> id -> string -> (unit, [`Msg of string]) result = "octez_riscv_storage_export_snapshot" +external octez_riscv_proof_start_state: proof -> bytes = "octez_riscv_proof_start_state" +external octez_riscv_proof_stop_state: proof -> bytes = "octez_riscv_proof_stop_state" +external octez_riscv_verify_proof: input option -> proof -> input_request option = "octez_riscv_verify_proof" +external octez_riscv_produce_proof: input option -> state -> proof option = "octez_riscv_produce_proof" diff --git a/src/riscv/lib/src/ocaml_api.rs b/src/riscv/lib/src/ocaml_api.rs index 283a1f3855db..874c3f11a71e 100644 --- a/src/riscv/lib/src/ocaml_api.rs +++ b/src/riscv/lib/src/ocaml_api.rs @@ -51,6 +51,13 @@ pub enum Input<'a> { Reveal(RevealData<'a>), } +/// A value of this type could only be returned as part of successfully verifying +/// a proof, which is not yet implemented. It is therefore only mocked for now. +#[ocaml::sig] +pub struct InputRequest; + +ocaml::custom!(InputRequest); + impl From for Status { fn from(item: PvmStatus) -> Self { Status::try_from(item as u8).expect("Invalid conversion") @@ -309,3 +316,39 @@ pub unsafe fn octez_riscv_storage_export_snapshot( ocaml::Value::hash_variant(gc, "Msg", Some(s.to_value(gc))) }) } + +/// Proofs +#[ocaml::sig] +pub struct Proof; + +ocaml::custom!(Proof); + +#[ocaml::func] +#[ocaml::sig("proof -> bytes")] +pub fn octez_riscv_proof_start_state(_proof: Pointer) -> [u8; 32] { + todo!() +} + +#[ocaml::func] +#[ocaml::sig("proof -> bytes")] +pub fn octez_riscv_proof_stop_state(_proof: Pointer) -> [u8; 32] { + todo!() +} + +#[ocaml::func] +#[ocaml::sig("input option -> proof -> input_request option")] +pub unsafe fn octez_riscv_verify_proof( + _proof: Pointer, + _input: Option, +) -> Option> { + None +} + +#[ocaml::func] +#[ocaml::sig("input option -> state -> proof option")] +pub unsafe fn octez_riscv_produce_proof( + _input: Option, + _state: Pointer, +) -> Option> { + None +} -- GitLab