From 745461a75aa9461377ed400071dac104dae8aa66 Mon Sep 17 00:00:00 2001 From: Hantang Sun Date: Thu, 8 Aug 2024 15:49:53 +0100 Subject: [PATCH] Implement ec_pairing_check host function --- manifest/product_octez.ml | 1 + src/lib_scoru_wasm/fast/funcs.ml | 21 ++++- src/lib_scoru_wasm/host_funcs.ml | 87 +++++++++++++++++ src/lib_scoru_wasm/host_funcs.mli | 9 ++ src/lib_scoru_wasm/test/dune | 3 +- src/lib_scoru_wasm/test/test_crypto.ml | 113 +++++++++++++++++++++++ src/lib_scoru_wasm/test/test_wasm_pvm.ml | 28 ++++++ 7 files changed, 260 insertions(+), 2 deletions(-) create mode 100644 src/lib_scoru_wasm/test/test_crypto.ml diff --git a/manifest/product_octez.ml b/manifest/product_octez.ml index b782604a5967..75493b4bd96b 100644 --- a/manifest/product_octez.ml +++ b/manifest/product_octez.ml @@ -4790,6 +4790,7 @@ let _octez_scoru_wasm_tests = "test_wasm_pvm_encodings"; "test_wasm_pvm"; "test_wasm_vm"; + "test_crypto"; ] ~path:"src/lib_scoru_wasm/test" ~opam:"octez-l2-libs" diff --git a/src/lib_scoru_wasm/fast/funcs.ml b/src/lib_scoru_wasm/fast/funcs.ml index f9bafd94cc72..4dd3e877a4b9 100644 --- a/src/lib_scoru_wasm/fast/funcs.ml +++ b/src/lib_scoru_wasm/fast/funcs.ml @@ -308,6 +308,25 @@ let make ~version ~reveal_builtins ~write_debug state = in return result) in + let ec_pairing_check_bls12_381 = + fn + (i32 @-> i32 @-> i32 @-> i32 @-> returning1 i32) + (fun point1_addr point2_addr point3_addr point4_addr -> + Lwt.map (Result.fold ~ok:Fun.id ~error:Fun.id) + @@ with_mem + @@ fun memory -> + let open Lwt_result_syntax in + let*! is_pairing_valid = + Host_funcs.Aux.ec_pairing_check_bls12_381 + ~memory + point1_addr + point2_addr + point3_addr + point4_addr + in + + return is_pairing_valid) + in let base = [ @@ -338,7 +357,7 @@ let make ~version ~reveal_builtins ~write_debug state = let v3 = v2 @ [("reveal", reveal_raw)] in let v4 = v3 in let v5 = v4 in - let v6 = v5 in + let v6 = v5 @ [("ec_pairing_check_bls12_381", ec_pairing_check_bls12_381)] in let extra = match version with | Wasm_pvm_state.V0 -> [] diff --git a/src/lib_scoru_wasm/host_funcs.ml b/src/lib_scoru_wasm/host_funcs.ml index 7b011a2e6557..7cc7d79fc339 100644 --- a/src/lib_scoru_wasm/host_funcs.ml +++ b/src/lib_scoru_wasm/host_funcs.ml @@ -282,6 +282,9 @@ module Aux = struct src:int32 -> num_bytes:int32 -> unit Lwt.t + + val ec_pairing_check_bls12_381 : + memory:memory -> int32 -> int32 -> int32 -> int32 -> int32 Lwt.t end module Make (M : Memory_access) : S with type memory = M.t = struct @@ -676,6 +679,37 @@ module Aux = struct match implem with | Builtins.Noop -> write_debug_impl | Printer f -> alternate_write_debug_impl ~f + + let ec_pairing_check_bls12_381 ~memory point1_addr point2_addr point3_addr + point4_addr = + let open Lwt_syntax in + let* point1_bytes = M.load_bytes memory point1_addr 48 in + let* point2_bytes = M.load_bytes memory point2_addr 96 in + let* point3_bytes = M.load_bytes memory point3_addr 48 in + let* point4_bytes = M.load_bytes memory point4_addr 96 in + + match (point1_bytes, point2_bytes, point3_bytes, point4_bytes) with + | Ok point1_bytes, Ok point2_bytes, Ok point3_bytes, Ok point4_bytes -> ( + let point1_opt = + Bls12_381.G1.of_compressed_bytes_opt (Bytes.of_string point1_bytes) + in + let point2_opt = + Bls12_381.G2.of_compressed_bytes_opt (Bytes.of_string point2_bytes) + in + let point3_opt = + Bls12_381.G1.of_compressed_bytes_opt (Bytes.of_string point3_bytes) + in + let point4_opt = + Bls12_381.G2.of_compressed_bytes_opt (Bytes.of_string point4_bytes) + in + + match (point1_opt, point2_opt, point3_opt, point4_opt) with + | Some point1, Some point2, Some point3, Some point4 -> + Lwt.return @@ Int32.of_int @@ Bool.to_int + @@ Bls12_381.Pairing.pairing_check + [(point1, point2); (point3, point4)] + | _ -> Lwt.return Int32.zero) + | _ -> Lwt.return Int32.zero end include Make (Memory_access_interpreter) @@ -1379,6 +1413,45 @@ let store_write = store_write_ticks key_length num_bytes code ) | _ -> raise Bad_input) +let ec_pairing_check_bls12_381 = + Host_funcs.Host_func + (fun _input_buffer _output_buffer durable memories inputs -> + match inputs with + | [ + Values.(Num (I32 point1_addr)); + Values.(Num (I32 point2_addr)); + Values.(Num (I32 point3_addr)); + Values.(Num (I32 point4_addr)); + ] -> + let open Lwt.Syntax in + let* memory = retrieve_memory memories in + let durable = Durable.of_storage_exn durable in + + let* is_pairing_valid = + Aux.ec_pairing_check_bls12_381 + ~memory + point1_addr + point2_addr + point3_addr + point4_addr + in + + Lwt.return + ( Durable.to_storage durable, + [value is_pairing_valid], + Z.of_int 120_000_000 ) + | _ -> raise Bad_input) + +let ec_pairing_check_bls12_381_type = + let input_types = + Types.[NumType I32Type; NumType I32Type; NumType I32Type; NumType I32Type] + |> Vector.of_list + in + let output_types = Vector.of_list Types.[NumType I32Type] in + Types.FuncType (input_types, output_types) + +let ec_pairing_check_bls12_381_name = "tezos_ec_pairing_check_bls12_381" + let lookup_opt ~version name = let v1_and_above ty name = match version with @@ -1395,6 +1468,11 @@ let lookup_opt ~version name = | Wasm_pvm_state.V0 | V1 | V2 -> None | V3 | V4 | V5 | V6 -> Some (ExternFunc (HostFunc (ty, name))) in + let v6_and_above ty name = + match version with + | Wasm_pvm_state.V0 | V1 | V2 | V3 | V4 | V5 -> None + | V6 -> Some (ExternFunc (HostFunc (ty, name))) + in match name with | "read_input" -> Some (ExternFunc (HostFunc (read_input_type, read_input_name))) @@ -1432,6 +1510,10 @@ let lookup_opt ~version name = | "store_create" -> v1_and_above store_create_type store_create_name | "store_exists" -> v2_and_above store_exists_type store_exists_name | "reveal" -> v3_and_above reveal_raw_type reveal_raw_name + | "ec_pairing_check_bls12_381" -> + v6_and_above + ec_pairing_check_bls12_381_type + ec_pairing_check_bls12_381_name | _ -> None let lookup ~version name = @@ -1456,6 +1538,7 @@ let base = (reveal_metadata_name, reveal_metadata); (store_read_name, store_read); (store_write_name, store_write); + (ec_pairing_check_bls12_381_name, ec_pairing_check_bls12_381); ] let with_write_debug ~write_debug:implem builder = @@ -1585,4 +1668,8 @@ module Internal_for_tests = struct let store_get_hash = Func.HostFunc (store_get_hash_type, store_get_hash_name) let write_debug = Func.HostFunc (write_debug_type, write_debug_name) + + let ec_pairing_check_bls12_381 = + Func.HostFunc + (ec_pairing_check_bls12_381_type, ec_pairing_check_bls12_381_name) end diff --git a/src/lib_scoru_wasm/host_funcs.mli b/src/lib_scoru_wasm/host_funcs.mli index 3714af31ecaf..1307fe2ea713 100644 --- a/src/lib_scoru_wasm/host_funcs.mli +++ b/src/lib_scoru_wasm/host_funcs.mli @@ -306,6 +306,12 @@ module Aux : sig src:int32 -> num_bytes:int32 -> unit Lwt.t + + (** [ec_pairing_check_bls12_381 point1 point2 point3 point4] + returns 0 if any points is incorrectly encoded, otherwise returns + [pairing (point1, point2) * pairing (point3, point4) == 1]. *) + val ec_pairing_check_bls12_381 : + memory:memory -> int32 -> int32 -> int32 -> int32 -> int32 Lwt.t end module Make (Memory_access : Memory_access) : @@ -397,4 +403,7 @@ module Internal_for_tests : sig val store_get_hash : Tezos_webassembly_interpreter.Instance.func_inst val write_debug : Tezos_webassembly_interpreter.Instance.func_inst + + val ec_pairing_check_bls12_381 : + Tezos_webassembly_interpreter.Instance.func_inst end diff --git a/src/lib_scoru_wasm/test/dune b/src/lib_scoru_wasm/test/dune index fd3abfb7f53d..80396890b692 100644 --- a/src/lib_scoru_wasm/test/dune +++ b/src/lib_scoru_wasm/test/dune @@ -48,7 +48,8 @@ test_wasm_encoding test_wasm_pvm_encodings test_wasm_pvm - test_wasm_vm)) + test_wasm_vm + test_crypto)) (executable (name main) diff --git a/src/lib_scoru_wasm/test/test_crypto.ml b/src/lib_scoru_wasm/test/test_crypto.ml new file mode 100644 index 000000000000..ce3ed43c7040 --- /dev/null +++ b/src/lib_scoru_wasm/test/test_crypto.ml @@ -0,0 +1,113 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2024 Trili Tech *) +(* *) +(* Permission is hereby granted, free of charge, to any person obtaining a *) +(* copy of this software and associated documentation files (the "Software"),*) +(* to deal in the Software without restriction, including without limitation *) +(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) +(* and/or sell copies of the Software, and to permit persons to whom the *) +(* Software is furnished to do so, subject to the following conditions: *) +(* *) +(* The above copyright notice and this permission notice shall be included *) +(* in all copies or substantial portions of the Software. *) +(* *) +(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) +(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) +(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) +(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) +(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) +(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) +(* DEALINGS IN THE SOFTWARE. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Cryptographic_host_functions + Invocation: dune exec src/lib_scoru_wasm/test/main.exe -- --file test_crypto.ml + Subject: Cryptographic host functions tests for the tezos-scoru-wasm library +*) + +open Tezos_webassembly_interpreter +open Tezos_scoru_wasm +open Wasm_utils + +let test_ec_pairing_check ~version () = + let open Lwt_syntax in + let paring_check_with_point point1_x point1_y point2_x point2_y = + let* durable = make_durable [] in + let addr1 = 10l in + let addr2 = Int32.add addr1 48l in + let addr3 = Int32.add addr2 96l in + let addr4 = Int32.add addr3 48l in + + let src = 10l in + let module_reg, module_key, host_funcs_registry = + make_module_inst + ~version + (List.map + Bytes.to_string + [ + Bls12_381.G1.to_compressed_bytes point1_x; + Bls12_381.G2.to_compressed_bytes point1_y; + Bls12_381.G1.to_compressed_bytes point2_x; + Bls12_381.G2.to_compressed_bytes point2_y; + ]) + src + in + + let values = + Values. + [Num (I32 addr1); Num (I32 addr2); Num (I32 addr3); Num (I32 addr4)] + in + + let* _, res = + Eval.invoke + ~module_reg + ~caller:module_key + ~durable + host_funcs_registry + Host_funcs.Internal_for_tests.ec_pairing_check_bls12_381 + values + in + + let expected_result = + if + Bls12_381.Pairing.pairing_check + [(point1_x, point1_y); (point2_x, point2_y)] + then 1l + else 0l + in + + assert (res = [Num (I32 expected_result)]) ; + + Lwt.return_ok () + in + + let* _ = + paring_check_with_point + Bls12_381.G1.zero + Bls12_381.G2.zero + Bls12_381.G1.zero + Bls12_381.G2.zero + in + + let* _ = + paring_check_with_point + Bls12_381.G1.one + Bls12_381.G2.one + Bls12_381.G1.one + Bls12_381.G2.one + in + + Lwt.return_ok () + +let tests = + Tztest_helper.tztests_with_all_pvms + [("ec_pairing_check", `Quick, test_ec_pairing_check)] + +let () = + Alcotest_lwt.run ~__FILE__ "test lib scoru wasm" [("Crypto", tests)] + |> Lwt_main.run diff --git a/src/lib_scoru_wasm/test/test_wasm_pvm.ml b/src/lib_scoru_wasm/test/test_wasm_pvm.ml index 6ea681f84707..046751650ec1 100644 --- a/src/lib_scoru_wasm/test/test_wasm_pvm.ml +++ b/src/lib_scoru_wasm/test/test_wasm_pvm.ml @@ -486,6 +486,26 @@ let try_availability_above_v1_only ~version import_name import_params assert (predicate state) ; Lwt_result_syntax.return_unit +let try_availability_above_v6_only ~version import_name import_params + import_results () = + let open Lwt_syntax in + let* tree = + initial_tree + ~version + ~from_binary:false + (nop_module import_name import_params import_results) + in + let* tree = set_empty_inbox_step 0l tree in + let* tree = eval_until_input_or_reveal_requested tree in + let* state = Wasm.Internal_for_tests.get_tick_state tree in + let predicate state = + match version with + | V0 | V1 | V2 | V3 | V4 | V5 -> is_stuck state + | V6 -> not (is_stuck state) + in + assert (predicate state) ; + Lwt_result_syntax.return_unit + let try_run_store_get_hash ~version = try_availability_above_v1_only ~version @@ -507,6 +527,13 @@ let try_run_store_create ~version = ["i32"; "i32"; "i32"] ["i32"] +let try_run_ec_pairing_check ~version = + try_availability_above_v6_only + ~version + "ec_pairing_check_bls12_381" + ["i32"; "i32"; "i32"; "i32"] + ["i32"] + let test_modify_read_only_storage_kernel ~version () = let open Lwt_syntax in let module_ = @@ -1789,6 +1816,7 @@ let tests = try_run_store_get_hash ); ("Test store_delete_value available", `Quick, try_run_store_delete_value); ("Test store_create available", `Quick, try_run_store_create); + ("Test ec_pairing_check available", `Quick, try_run_ec_pairing_check); ( "Test unreachable kernel (tick per tick)", `Quick, fun ~version -> -- GitLab