From 62f6f6a2a24dc6ed44644907ac4e09319a11d152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Thir=C3=A9?= Date: Fri, 29 Jul 2022 16:20:55 +0200 Subject: [PATCH] DAL: Refactor the way SRS is handled --- CHANGES.rst | 4 + src/bin_dal_node/cryptobox.ml | 22 +- src/bin_dal_node/daemon.ml | 18 +- src/bin_dal_node/services.ml | 4 +- src/bin_dal_node/slot_manager.ml | 7 +- src/bin_dal_node/slot_manager.mli | 1 - src/bin_node/node_config_file.ml | 51 +- src/bin_node/node_config_file.mli | 16 + src/bin_node/node_run_command.ml | 3 + src/lib_base/dal_srs.ml | 83 ++++ src/lib_base/dal_srs.mli | 34 ++ src/lib_crypto_dal/dal_cryptobox.ml | 443 +++++++----------- src/lib_crypto_dal/dal_cryptobox.mli | 72 +-- src/lib_crypto_dal/dal_cryptobox_intf.ml | 34 +- src/lib_crypto_dal/test/test_dal_cryptobox.ml | 145 +++--- src/lib_protocol_environment/sigs/v7.ml | 30 +- src/lib_protocol_environment/sigs/v7/dal.mli | 30 +- tezt/lib_tezos/rollup.ml | 37 +- tezt/lib_tezos/rollup.mli | 2 +- tezt/tests/dal.ml | 38 +- 20 files changed, 557 insertions(+), 517 deletions(-) create mode 100644 src/lib_base/dal_srs.ml create mode 100644 src/lib_base/dal_srs.mli diff --git a/CHANGES.rst b/CHANGES.rst index 49877f3c87a5..49434da8a2f4 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -25,6 +25,10 @@ be documented here either. Node ---- +- Add a field ``dal`` in the node's configuration file. This field is + for a feature which is being developed and should not be + modified. It should be used only for testing. + Client ------ diff --git a/src/bin_dal_node/cryptobox.ml b/src/bin_dal_node/cryptobox.ml index a1770b7bbcb7..2763c5eda883 100644 --- a/src/bin_dal_node/cryptobox.ml +++ b/src/bin_dal_node/cryptobox.ml @@ -44,6 +44,26 @@ type slot_header = commitment let slot_header_encoding = Commitment.encoding +type error += Cryptobox_initialisation_failed of string + +let () = + register_error_kind + `Permanent + ~id:"dal.node.cryptobox.initialisation_failed" + ~title:"Cryptobox initialisation failed" + ~description:"Unable to initialise the cryptobox parameters" + ~pp:(fun ppf msg -> + Format.fprintf + ppf + "Unable to initialise the cryptobox parameters. Reason: %s" + msg) + Data_encoding.(obj1 (req "error" string)) + (function Cryptobox_initialisation_failed str -> Some str | _ -> None) + (fun str -> Cryptobox_initialisation_failed str) + let init () = let open Constants in - make ~redundancy_factor ~segment_size ~slot_size ~number_of_shards + let open Result_syntax in + match make ~redundancy_factor ~segment_size ~slot_size ~number_of_shards with + | Ok cryptobox -> return cryptobox + | Error (`Fail msg) -> fail [Cryptobox_initialisation_failed msg] diff --git a/src/bin_dal_node/daemon.ml b/src/bin_dal_node/daemon.ml index 623965817796..1671a9f25162 100644 --- a/src/bin_dal_node/daemon.ml +++ b/src/bin_dal_node/daemon.ml @@ -23,18 +23,14 @@ (* *) (*****************************************************************************) -type ctxt = { - config : Configuration.t; - srs : Cryptobox.srs; - dal_constants : Cryptobox.t; -} +type ctxt = {config : Configuration.t; dal_constants : Cryptobox.t} module RPC_server = struct let register_split_slot ctxt store dir = RPC_directory.register0 dir (Services.split_slot ()) - (Services.handle_split_slot ctxt.dal_constants ctxt.srs store) + (Services.handle_split_slot ctxt.dal_constants store) let register_show_slot ctxt store dir = RPC_directory.register @@ -87,9 +83,13 @@ let run ~data_dir ~no_trusted_setup:_ _ctxt = let* config = Configuration.load ~data_dir in let config = {config with data_dir} in let*! store = Store.init config in - let dal_constants = Cryptobox.init () in - let*? srs = Cryptobox.load_srs dal_constants in - let ctxt = {config; srs; dal_constants} in + let*? g1_path, g2_path = Tezos_base.Dal_srs.find_trusted_setup_files () in + let* initialisation_parameters = + Cryptobox.initialisation_parameters_from_files ~g1_path ~g2_path + in + let*? () = Cryptobox.load_parameters initialisation_parameters in + let*? dal_constants = Cryptobox.init () in + let ctxt = {config; dal_constants} in let* rpc_server = RPC_server.(start config (register ctxt store)) in let _ = RPC_server.install_finalizer rpc_server in let*! () = diff --git a/src/bin_dal_node/services.ml b/src/bin_dal_node/services.ml index 4ef79c77c6a1..994e0b5da4cd 100644 --- a/src/bin_dal_node/services.ml +++ b/src/bin_dal_node/services.ml @@ -59,11 +59,11 @@ let shard () = ~output:Cryptobox.shard_encoding RPC_path.(open_root / "shard" /: Cryptobox.Commitment.rpc_arg /: shard_arg) -let handle_split_slot dal_constants srs store fill slot = +let handle_split_slot dal_constants store fill slot = let open Lwt_result_syntax in let slot = String.to_bytes slot in let slot = if fill then Slot_manager.Utils.fill_x00 slot else slot in - let+ commitment = Slot_manager.split_and_store dal_constants srs store slot in + let+ commitment = Slot_manager.split_and_store dal_constants store slot in Cryptobox.Commitment.to_b58check commitment let handle_slot dal_constants store (_, commitment) trim () = diff --git a/src/bin_dal_node/slot_manager.ml b/src/bin_dal_node/slot_manager.ml index 45b648dd17cf..fc9172a5c3e8 100644 --- a/src/bin_dal_node/slot_manager.ml +++ b/src/bin_dal_node/slot_manager.ml @@ -112,11 +112,11 @@ let save store slot_header shards = return metadata) shards -let split_and_store cb_constants srs store slot = +let split_and_store cb_constants store slot = let r = let open Result_syntax in let* polynomial = Cryptobox.polynomial_from_slot cb_constants slot in - let* commitment = Cryptobox.commit srs polynomial in + let commitment = Cryptobox.commit cb_constants polynomial in return (polynomial, commitment) in let open Lwt_result_syntax in @@ -129,8 +129,7 @@ let split_and_store cb_constants srs store slot = emit stored_slot (Bytes.length slot, Cryptobox.IntMap.cardinal shards)) in Lwt.return_ok commitment - | Error (`Degree_exceeds_srs_length msg) | Error (`Slot_wrong_size msg) -> - Lwt.return_error [Splitting_failed msg] + | Error (`Slot_wrong_size msg) -> Lwt.return_error [Splitting_failed msg] let get_shard store slot_header shard_id = let open Lwt_result_syntax in diff --git a/src/bin_dal_node/slot_manager.mli b/src/bin_dal_node/slot_manager.mli index 24deff4058bb..794606a494f8 100644 --- a/src/bin_dal_node/slot_manager.mli +++ b/src/bin_dal_node/slot_manager.mli @@ -35,7 +35,6 @@ [cb_constants] and trusted setup [ts] *) val split_and_store : Cryptobox.t -> - Cryptobox.srs -> Store.t -> Cryptobox.slot -> Cryptobox.slot_header tzresult Lwt.t diff --git a/src/bin_node/node_config_file.ml b/src/bin_node/node_config_file.ml index 7ce0c91b3d48..2b6231a3fb57 100644 --- a/src/bin_node/node_config_file.ml +++ b/src/bin_node/node_config_file.ml @@ -416,6 +416,15 @@ let sugared_blockchain_network_encoding : blockchain_network Data_encoding.t = (fun x -> x); ]) +type dal = {activated : bool; srs_size : int option} + +let dal_encoding : dal Data_encoding.t = + let open Data_encoding in + conv + (fun {activated; srs_size} -> (activated, srs_size)) + (fun (activated, srs_size) -> {activated; srs_size}) + (obj2 (req "activated" bool) (req "srs_size" (option int31))) + type t = { data_dir : string; disable_config_validation : bool; @@ -426,6 +435,7 @@ type t = { shell : shell; blockchain_network : blockchain_network; metrics_addr : string list; + dal : dal; } and p2p = { @@ -526,6 +536,8 @@ let default_shell = let default_disable_config_validation = false +let default_dal : dal = {activated = false; srs_size = None} + let default_config = { data_dir = default_data_dir; @@ -537,6 +549,7 @@ let default_config = blockchain_network = blockchain_network_mainnet; disable_config_validation = default_disable_config_validation; metrics_addr = []; + dal = default_dal; } let limit : P2p.limits Data_encoding.t = @@ -1194,6 +1207,7 @@ let encoding = shell; blockchain_network; metrics_addr; + dal; } -> ( data_dir, disable_config_validation, @@ -1203,7 +1217,8 @@ let encoding = internal_events, shell, blockchain_network, - metrics_addr )) + metrics_addr, + dal )) (fun ( data_dir, disable_config_validation, rpc, @@ -1212,7 +1227,8 @@ let encoding = internal_events, shell, blockchain_network, - metrics_addr ) -> + metrics_addr, + dal ) -> { disable_config_validation; data_dir; @@ -1223,8 +1239,9 @@ let encoding = shell; blockchain_network; metrics_addr; + dal; }) - (obj9 + (obj10 (dft "data-dir" ~description:"Location of the data dir on disk." @@ -1270,7 +1287,14 @@ let encoding = "metrics_addr" ~description:"Configuration of the Prometheus metrics endpoint" (list string) - default_config.metrics_addr)) + default_config.metrics_addr) + (dft + "dal" + ~description: + "USE FOR TESTING PURPOSE ONLY. Configuration for the \ + data-availibility layer" + dal_encoding + default_dal)) (* Abstract version of [Json_encoding.Cannot_destruct]: first argument is the string representation of the path, second argument is the error message @@ -1621,3 +1645,22 @@ let bootstrap_peers config = Option.value ~default:config.blockchain_network.default_bootstrap_peers config.p2p.bootstrap_peers + +let init_dal dal_config = + let open Lwt_result_syntax in + if dal_config.activated then + let open Tezos_crypto_dal.Dal_cryptobox in + let* initialisation_parameters = + match dal_config.srs_size with + | None -> + let*? g1_path, g2_path = + Tezos_base.Dal_srs.find_trusted_setup_files () + in + initialisation_parameters_from_files ~g1_path ~g2_path + | Some slot_size -> + return + (Internal_for_tests.initialisation_parameters_from_slot_size + ~slot_size) + in + Lwt.return (load_parameters initialisation_parameters) + else return_unit diff --git a/src/bin_node/node_config_file.mli b/src/bin_node/node_config_file.mli index 933d245810c9..205c1b3cf2ab 100644 --- a/src/bin_node/node_config_file.mli +++ b/src/bin_node/node_config_file.mli @@ -26,6 +26,18 @@ type chain_name = Distributed_db_version.Name.t +(** node parameters for the DAL. *) +type dal = { + activated : bool; + (** [true] if the DAL is activated ([false] by default). This may have + an impact on the loading time of the node. *) + srs_size : int option; + (** If [None] (the default), the srs is read from the srs files. This + is the value expected for production. For testing purposes, we may + want to compute the srs instead but this is unsafe. In that case, a + size must be specified. *) +} + type blockchain_network = { alias : string option; (** as given to [--network], only for built-in networks *) @@ -56,6 +68,7 @@ type t = { shell : shell; blockchain_network : blockchain_network; metrics_addr : string list; + dal : dal; } and p2p = { @@ -187,3 +200,6 @@ val encoding : t Data_encoding.t (** Return [p2p.bootstrap_peers] if not [None], [network.default_bootstrap_peers] otherwise. *) val bootstrap_peers : t -> string list + +(** [init_dal dal] initialises the DAL according to the dal configuration [dal]. *) +val init_dal : dal -> unit tzresult Lwt.t diff --git a/src/bin_node/node_run_command.ml b/src/bin_node/node_run_command.ml index a26fc15a3c56..f37e1abd5b8b 100644 --- a/src/bin_node/node_run_command.ml +++ b/src/bin_node/node_run_command.ml @@ -519,6 +519,8 @@ let init_zcash () = "Failed to initialize Zcash parameters: %s" (Printexc.to_string exn)) +let init_dal dal_config = Node_config_file.init_dal dal_config + let run ?verbosity ?sandbox ?target ?(cli_warnings = []) ?ignore_testchain_warning ~singleprocess ~force_history_mode_switch (config : Node_config_file.t) = @@ -549,6 +551,7 @@ let run ?verbosity ?sandbox ?target ?(cli_warnings = []) Tezos_version.Current_git_info.abbreviated_commit_hash ) in let*! () = init_zcash () in + let* () = init_dal config.dal in let*! node = init_node ?sandbox diff --git a/src/lib_base/dal_srs.ml b/src/lib_base/dal_srs.ml new file mode 100644 index 000000000000..3f628cdea782 --- /dev/null +++ b/src/lib_base/dal_srs.ml @@ -0,0 +1,83 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type Error_monad.error += No_trusted_setup of string list + +let () = + Error_monad.register_error_kind + `Permanent + ~id:"node.config.trusted_setup_not_found" + ~title:"No trusted setup found" + ~description:"No trusted setup found in the explored paths" + ~pp:(fun ppf locations -> + Format.fprintf + ppf + "@[cannot find Trusted setup in any of:@,%a@]@." + (Format.pp_print_list (fun fmt -> Format.fprintf fmt "- %s")) + locations) + Data_encoding.(obj1 (req "paths" (list string))) + (function No_trusted_setup parameter -> Some parameter | _ -> None) + (fun parameter -> No_trusted_setup parameter) + +(* FIXME https://gitlab.com/tezos/tezos/-/issues/3410 + + This function should be factored out with the one of sapling. *) +let find_trusted_setup_files ?(getenv_opt = Sys.getenv_opt) + ?(getcwd = Sys.getcwd) ?(file_exists = Sys.file_exists) () = + let ( // ) = Filename.concat in + let env ?split name path = + match getenv_opt name with + | None -> [] + | Some value -> ( + match split with + | None -> [Filename.concat value path] + | Some char -> + List.map (fun dir -> dir // path) (String.split_on_char char value)) + in + let cwd path = try [getcwd () // path] with Sys_error _ -> [] in + let candidate_directories = + env "XDG_DATA_HOME" ".local/share/dal-trusted-setup" + @ env ~split:':' "XDG_DATA_DIRS" "dal-trusted-setup" + @ env "OPAM_SWITCH_PREFIX" "share/dal-trusted-setup" + @ env "PWD" "_opam/share/dal-trusted-setup" + @ cwd "_opam/share/dal-trusted-setup" + @ env "HOME" ".dal-trusted-setup" + @ env "HOME" ".local/share/dal-trusted-setup" + @ env "HOMEBREW_PREFIX" "share/dal-trusted-setup" + @ ["/usr/local/share/dal-trusted-setup"; "/usr/share/dal-trusted-setup"] + in + (* Files we are looking for. *) + let g1_file = "srs_zcash_g1" in + let g2_file = "srs_zcash_g2" in + (* Find the first candidate directory that contains the expected files. *) + let contains_trusted_setup_files directory = + file_exists (directory // g1_file) && file_exists (directory // g2_file) + in + match List.find_opt contains_trusted_setup_files candidate_directories with + | None -> Error [No_trusted_setup candidate_directories] + | Some directory -> + let g1_path = directory // g1_file in + let g2_path = directory // g2_file in + Ok (g1_path, g2_path) diff --git a/src/lib_base/dal_srs.mli b/src/lib_base/dal_srs.mli new file mode 100644 index 000000000000..4942d10e074c --- /dev/null +++ b/src/lib_base/dal_srs.mli @@ -0,0 +1,34 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** [find_trusted_setup_files] returns the path of the two files + necessary to initialize cryptographic primitives used by the + DAL. See {!module:Tezos-crypto_dal.Dal_cryptobox}. *) +val find_trusted_setup_files : + ?getenv_opt:(string -> string option) -> + ?getcwd:(unit -> string) -> + ?file_exists:(string -> bool) -> + unit -> + (string * string) Error_monad.tzresult diff --git a/src/lib_crypto_dal/dal_cryptobox.ml b/src/lib_crypto_dal/dal_cryptobox.ml index 34b06533c6da..81a9b2f1b849 100644 --- a/src/lib_crypto_dal/dal_cryptobox.ml +++ b/src/lib_crypto_dal/dal_cryptobox.ml @@ -27,11 +27,7 @@ open Error_monad include Dal_cryptobox_intf module Base58 = Tezos_crypto.Base58 -type error += - | Failed_to_load_trusted_setup of string - | No_trusted_setup of string list - | Trusted_setup_too_small of - int (* FIXME: "SRS asked (%d) too big for %s" d srsfile *) +type error += Failed_to_load_trusted_setup of string let () = register_error_kind @@ -44,21 +40,67 @@ let () = Data_encoding.(obj1 (req "msg" string)) (function | Failed_to_load_trusted_setup parameter -> Some parameter | _ -> None) - (fun parameter -> Failed_to_load_trusted_setup parameter) ; - register_error_kind - `Permanent - ~id:"dal.node.trusted_setup_not_found" - ~title:"No trusted setup found" - ~description:"No trusted setup found in the explored paths" - ~pp:(fun ppf locations -> - Format.fprintf - ppf - "@[cannot find Trusted setup in any of:@,%a@]@." - (Format.pp_print_list (fun fmt -> Format.fprintf fmt "- %s")) - locations) - Data_encoding.(obj1 (req "paths" (list string))) - (function No_trusted_setup parameter -> Some parameter | _ -> None) - (fun parameter -> No_trusted_setup parameter) + (fun parameter -> Failed_to_load_trusted_setup parameter) + +type initialisation_parameters = { + srs_g1 : Bls12_381.G1.t array; + srs_g2 : Bls12_381.G2.t array; +} + +(* Initialisation parameters are supposed to be instantiated once. *) +let initialisation_parameters = ref None + +type error += Dal_initialisation_twice + +(* This function is expected to be called once. *) +let load_parameters parameters = + let open Result_syntax in + match !initialisation_parameters with + | None -> + initialisation_parameters := Some parameters ; + return_unit + | Some _ -> fail [Dal_initialisation_twice] + +(* FIXME https://gitlab.com/tezos/tezos/-/issues/3400 + + An integrity check is run to ensure the validity of the files. *) + +let initialisation_parameters_from_files ~g1_path ~g2_path = + let open Lwt_result_syntax in + (* FIXME https://gitlab.com/tezos/tezos/-/issues/3409 + + The `21` constant is the logarithmic size of the file. Can this + constant be recomputed? Even though it should be determined by + the integrity check. *) + let logarithmic_size = 21 in + let srs_g1 = + Bls12_381_polynomial.Srs.M.( + to_array (load_from_file g1_path logarithmic_size)) + in + let g2_size_compressed = Bls12_381.G2.size_in_bytes / 2 in + let buf = Bytes.create g2_size_compressed in + (* FIXME https://gitlab.com/tezos/tezos/-/issues/3416 + + The reading is not in `Lwt`. Hence it can be an issue that this + reading is blocking. To make the interface future proof, we + already put this function in the [Lwt] monad. *) + let read ic = + Stdlib.really_input ic buf 0 g2_size_compressed ; + Bls12_381.G2.of_compressed_bytes_exn buf + in + let ic = open_in g2_path in + let srs_g2 = Array.init (1 lsl logarithmic_size) (fun _ -> read ic) in + close_in ic ; + return {srs_g1; srs_g2} + +(* The srs is made of the initialisation_parameters and two + well-choosen points. Building the srs from the initialisation + parameters is almost cost-free. *) +type srs = { + raw : initialisation_parameters; + kate_amortized_srs_g2_shards : Bls12_381.G2.t; + kate_amortized_srs_g2_segments : Bls12_381.G2.t; +} module Inner = struct (* Scalars are elements of the prime field Fr from BLS. *) @@ -99,12 +141,6 @@ module Inner = struct type shards_proofs_precomputation = Scalar.t array * segment_proof array array - type trusted_setup_files = { - srs_g1_file : string; - srs_g2_file : string; - logarithm_size : int; - } - module Encoding = struct open Data_encoding @@ -239,7 +275,7 @@ module Inner = struct (* Length of a shard in terms of scalar elements. *) nb_segments : int; (* Number of slot segments. *) - segment_len : int; + segment_length : int; remaining_bytes : int; evaluations_log : int; (* Log of the number of evaluations that constitute an erasure encoded @@ -247,9 +283,12 @@ module Inner = struct evaluations_per_proof_log : int; (* Log of the number of evaluations contained in a shard. *) proofs_log : int; (* Log of th number of shards proofs. *) + srs : srs; } - let check_params t = + let ensure_validity t = + let open Result_syntax in + let srs_size = Array.length t.srs.raw.srs_g1 in let is_pow_of_two x = let logx = Z.(log2 (of_int x)) in 1 lsl logx = x @@ -262,23 +301,47 @@ module Inner = struct then (* According to the specification the lengths of a slot a slot segment are in MiB *) - invalid_arg "Wrong slot size: expected MiB" + fail (`Fail "Wrong slot size: expected MiB") else if not (Z.(log2 (of_int t.n)) <= 32 && is_pow_of_two t.k && t.n > t.k) then (* n must be at most 2^32, the biggest subgroup of 2^i roots of unity in the multiplicative group of Fr, because the FFTs operate on such groups. *) - invalid_arg "Wrong computed size for n" - else if not (is_pow_of_two t.number_of_shards && t.n > t.number_of_shards) - then invalid_arg "Shards not containing at least two elements" - else () - (* Shards must contain at least two elements. *) - + fail (`Fail "Wrong computed size for n") + else if t.k > srs_size then + fail + (`Fail + (Format.asprintf + "SRS size is too small. Expected more than %d. Got %d" + t.k + srs_size)) + else return t + + let slot_as_polynomial_length ~slot_size = + 1 lsl Z.(log2up (of_int slot_size / of_int scalar_bytes_amount)) + + (* Error cases of this functions are not encapsulated into + `tzresult` for modularity reasons. *) let make ~redundancy_factor ~slot_size ~segment_size ~number_of_shards = - let k = 1 lsl Z.(log2up (of_int slot_size / of_int scalar_bytes_amount)) in + let open Result_syntax in + let k = slot_as_polynomial_length ~slot_size in let n = redundancy_factor * k in let shard_size = n / number_of_shards in let evaluations_log = Z.(log2 (of_int n)) in let evaluations_per_proof_log = Z.(log2 (of_int shard_size)) in + let segment_length = Int.div segment_size scalar_bytes_amount + 1 in + let* srs = + match !initialisation_parameters with + | None -> fail (`Fail "Dal_cryptobox.make: DAL was not initialisated.") + | Some raw -> + return + { + raw; + kate_amortized_srs_g2_shards = + Array.get raw.srs_g2 (1 lsl evaluations_per_proof_log); + kate_amortized_srs_g2_segments = + Array.get raw.srs_g2 (1 lsl Z.(log2up (of_int segment_length))); + } + in let t = { redundancy_factor; @@ -292,187 +355,15 @@ module Inner = struct domain_n = make_domain n; shard_size; nb_segments = slot_size / segment_size; - segment_len = Int.div segment_size scalar_bytes_amount + 1; + segment_length; remaining_bytes = segment_size mod scalar_bytes_amount; evaluations_log; evaluations_per_proof_log; proofs_log = evaluations_log - evaluations_per_proof_log; + srs; } in - check_params t ; - t - - (* The srs is an initialisation setup required by many primitives of - the cryptobox. For production code, this initialisation setup is - provided via files of size ~300MB. Loading those files can be done - once by the shell. However, the [srs] value depends on the - [slot_size] which is determined by the protocol. - - What we provide here is a mechanism to store at most two different - [srs] depending on two different slot sizes. using the [Ringo] - library (see {!val:srs_ring}). We also provide a cache mechanism to - avoid recomputing the [srs] if it was already computed once. *) - type srs = { - srs_g1 : Bls12_381.G1.t array; - srs_g2 : Bls12_381.G2.t array; - kate_amortized_srs_g2_shards : Bls12_381.G2.t; - kate_amortized_srs_g2_segments : Bls12_381.G2.t; - } - - let srs t : srs = - let module Scalar = Bls12_381.Fr in - let build_array init next len = - let xi = ref init in - Array.init len (fun _ -> - let i = !xi in - xi := next !xi ; - i) - in - let create_srs : - type t. - (module Bls12_381.CURVE with type t = t) -> int -> Scalar.t -> t array = - fun (module G) d x -> build_array G.(copy one) (fun g -> G.(mul g x)) d - in - let secret = - Scalar.of_string - "20812168509434597367146703229805575690060615791308155437936410982393987532344" - in - let srs_g1 = create_srs (module Bls12_381.G1) t.k secret in - let srs_g2 = create_srs (module Bls12_381.G2) t.k secret in - { - srs_g1; - srs_g2; - kate_amortized_srs_g2_shards = - Array.get srs_g2 (1 lsl t.evaluations_per_proof_log); - kate_amortized_srs_g2_segments = - Array.get srs_g2 (1 lsl Z.(log2up (of_int t.segment_len))); - } - - module SRS_ring = - (val Ringo.( - map_maker ~replacement:FIFO ~overflow:Strong ~accounting:Precise)) - (struct - include Int - - let hash = Hashtbl.hash - end) - - (* FIXME https://gitlab.com/tezos/tezos/-/issues/3408 - - We use [3] because a priori, we only need to support [2] protocols - at the same time. In case of an hard fork, we give one protocol - more for security. *) - let srs_ring = SRS_ring.create 3 - - (* FIXME https://gitlab.com/tezos/tezos/-/issues/3410 - - This function should be factored out with the one of sapling. *) - let find_trusted_setup ?(getenv_opt = Sys.getenv_opt) ?(getcwd = Sys.getcwd) - ?(file_exists = Sys.file_exists) () = - let ( // ) = Filename.concat in - let env ?split name path = - match getenv_opt name with - | None -> [] - | Some value -> ( - match split with - | None -> [Filename.concat value path] - | Some char -> - List.map - (fun dir -> dir // path) - (String.split_on_char char value)) - in - let cwd path = try [getcwd () // path] with Sys_error _ -> [] in - let candidate_directories = - env "XDG_DATA_HOME" ".local/share/dal-trusted-setup" - @ env ~split:':' "XDG_DATA_DIRS" "dal-trusted-setup" - @ env "OPAM_SWITCH_PREFIX" "share/dal-trusted-setup" - @ env "PWD" "_opam/share/dal-trusted-setup" - @ cwd "_opam/share/dal-trusted-setup" - @ env "HOME" ".dal-trusted-setup" - @ env "HOME" ".local/share/dal-trusted-setup" - @ env "HOMEBREW_PREFIX" "share/dal-trusted-setup" - @ ["/usr/local/share/dal-trusted-setup"; "/usr/share/dal-trusted-setup"] - in - (* Files we are looking for. *) - let srs_g1 = "srs_zcash_g1" in - let srs_g2 = "srs_zcash_g2" in - - (* Find the first candidate directory that contains the expected files. *) - let contains_trusted_setup_files directory = - file_exists (directory // srs_g1) && file_exists (directory // srs_g2) - in - match List.find_opt contains_trusted_setup_files candidate_directories with - | None -> Error [No_trusted_setup candidate_directories] - | Some directory -> - let srs_g1_file = directory // srs_g1 in - let srs_g2_file = directory // srs_g2 in - (* FIXME https://gitlab.com/tezos/tezos/-/issues/3409 - - An integrity check should ensure that only one SRS file is - expected. The `21` constant is the logarithmic size of this - file. A refactorisation, should ensure that this constant - is not needed or could be computed. *) - Ok {srs_g1_file; srs_g2_file; logarithm_size = 21} - - (* FIXME https://gitlab.com/tezos/tezos/-/issues/3400 - - An integrity check is run to ensure the validity of the files. *) - let build_trusted_setup_instance t ~srs_g1_file ~srs_g2_file ~logarithm_size = - assert (t.k < 1 lsl logarithm_size) ; - let srs_g1 = - Bls12_381_polynomial.Srs.M.(to_array (load_from_file srs_g1_file t.k)) - in - let g2_size_compressed = Bls12_381.G2.size_in_bytes / 2 in - let buf = Bytes.create g2_size_compressed in - (* FIXME https://gitlab.com/tezos/tezos/-/issues/3416 - - The reading is not in `Lwt`. Hence it can be an issue that this - reading is blocking. *) - let read ic = - Stdlib.really_input ic buf 0 g2_size_compressed ; - Bls12_381.G2.of_compressed_bytes_exn buf - in - let ic = open_in srs_g2_file in - let file_size = in_channel_length ic in - if file_size < t.k * g2_size_compressed then ( - close_in ic ; - Error [Trusted_setup_too_small file_size]) - else - let srs_g2 = Array.init t.k (fun _ -> read ic) in - close_in ic ; - Ok - { - srs_g1; - srs_g2; - kate_amortized_srs_g2_shards = - Array.get srs_g2 (1 lsl t.evaluations_per_proof_log); - kate_amortized_srs_g2_segments = - Array.get srs_g2 (1 lsl Z.(log2up (of_int t.segment_len))); - } - - (* FIXME https://gitlab.com/tezos/tezos/-/issues/3399 - - The reading of the files should be done beforehand. This - would ease the assumptions made by the protocol, and especially - avoid the issue that [load_srs] may fail because the file was not - found which is the responsibility of the shell. *) - let load_srs_from_file t = - match find_trusted_setup () with - | Ok {srs_g1_file; srs_g2_file; logarithm_size} -> - build_trusted_setup_instance t ~srs_g1_file ~srs_g2_file ~logarithm_size - | Error err -> Error err - - let load_srs t = - match SRS_ring.find_opt srs_ring t.k with - | None -> ( - match load_srs_from_file t with - | Ok srs -> - SRS_ring.replace srs_ring t.k srs ; - Ok srs - | Error err -> Error err) - | Some k -> Ok k - - let srs = srs + ensure_validity t let polynomial_degree = Polynomials.degree @@ -495,9 +386,9 @@ module Inner = struct let offset = ref 0 in let res = Array.init t.k (fun _ -> Scalar.(copy zero)) in for segment = 0 to t.nb_segments - 1 do - for elt = 0 to t.segment_len - 1 do + for elt = 0 to t.segment_length - 1 do if !offset > t.slot_size then () - else if elt = t.segment_len - 1 then ( + else if elt = t.segment_length - 1 then ( let dst = Bytes.create t.remaining_bytes in Bytes.blit slot !offset dst 0 t.remaining_bytes ; offset := !offset + t.remaining_bytes ; @@ -517,10 +408,10 @@ module Inner = struct Ok (Evaluations.interpolation_fft2 t.domain_k data) let eval_coset t eval slot offset segment = - for elt = 0 to t.segment_len - 1 do + for elt = 0 to t.segment_length - 1 do let idx = (elt * t.nb_segments) + segment in let coeff = Scalar.to_bytes (Array.get eval idx) in - if elt = t.segment_len - 1 then ( + if elt = t.segment_length - 1 then ( Bytes.blit coeff 0 slot !offset t.remaining_bytes ; offset := !offset + t.remaining_bytes) else ( @@ -670,26 +561,16 @@ module Inner = struct let commit' : type t. - (module Bls12_381.CURVE with type t = t) -> - scalar array -> - t array -> - (t, [> `Degree_exceeds_srs_length of string]) Result.t = + (module Bls12_381.CURVE with type t = t) -> scalar array -> t array -> t = fun (module G) p srs -> - if p = [||] then Ok G.(copy zero) - else if Array.(length p > length srs) then - Error - (`Degree_exceeds_srs_length - (Printf.sprintf - "polynomial degree, %i, exceeds srs’ length, %i." - (Array.length p) - (Array.length srs))) - else Ok (G.pippenger ~start:0 ~len:(Array.length p) srs p) + if p = [||] then G.(copy zero) + else G.pippenger ~start:0 ~len:(Array.length p) srs p - let commit trusted_setup p = + let commit t p = commit' (module Bls12_381.G1) (Polynomials.to_dense_coefficients p) - trusted_setup.srs_g1 + t.srs.raw.srs_g1 (* p(X) of degree n. Max degree that can be committed: d, which is also the SRS's length - 1. We take d = k - 1 since we don't want to commit @@ -702,27 +583,27 @@ module Inner = struct using the commitments for p and p X^{d-n}, and computing the commitment for X^{d-n} on G_2.*) - let prove_commitment trusted_setup p = + let prove_commitment t p = commit' (module Bls12_381.G1) Polynomials.( to_dense_coefficients (mul (Polynomials.of_coefficients [(Scalar.(copy one), 0)]) p)) - trusted_setup.srs_g1 + t.srs.raw.srs_g1 (* FIXME https://gitlab.com/tezos/tezos/-/issues/3389 Generalize this function to pass the degree in parameter. *) - let verify_commitment trusted_setup cm proof = + let verify_commitment t cm proof = let open Bls12_381 in let check = - match Array.get trusted_setup.srs_g2 0 with + match Array.get t.srs.raw.srs_g2 0 with | exception Invalid_argument _ -> false | commit_xk -> Pairing.pairing_check [(cm, commit_xk); (proof, G2.(negate (copy one)))] in - Ok check + check let inverse domain = let n = Array.length domain in @@ -832,25 +713,22 @@ module Inner = struct |> snd (* Part 3.2 verifier : verifies that f(w×domain.(i)) = evaluations.(i). *) - let verify cm_f (srs1, srs2l) domain (w, evaluations) proof = + let verify t cm_f srs_point domain (w, evaluations) proof = let open Bls12_381 in - let open Result_syntax in let h = interpolation_h_poly w domain evaluations in - let* cm_h = commit' (module G1) h srs1 in + let cm_h = commit' (module G1) h t.srs.raw.srs_g1 in let l = Domains.length domain in let sl_min_yl = - G2.(add srs2l (negate (mul (copy one) (Scalar.pow w (Z.of_int l))))) + G2.(add srs_point (negate (mul (copy one) (Scalar.pow w (Z.of_int l))))) in let diff_commits = G1.(add cm_h (negate cm_f)) in - Ok - (Pairing.pairing_check - [(diff_commits, G2.(copy one)); (proof, sl_min_yl)]) + Pairing.pairing_check [(diff_commits, G2.(copy one)); (proof, sl_min_yl)] - let precompute_shards_proofs t trusted_setup = + let precompute_shards_proofs t = preprocess_multi_reveals ~chunk_len:t.evaluations_per_proof_log ~degree:t.k - trusted_setup.srs_g1 + t.srs.raw.srs_g1 let _save_precompute_shards_proofs (preprocess : shards_proofs_precomputation) filename = @@ -875,8 +753,8 @@ module Inner = struct In_channel.close_noerr chan ; precomp - let prove_shards t srs p = - let preprocess = precompute_shards_proofs t srs in + let prove_shards t p = + let preprocess = precompute_shards_proofs t in multiple_multi_reveals ~chunk_len:t.evaluations_per_proof_log ~chunk_count:t.proofs_log @@ -884,18 +762,18 @@ module Inner = struct ~preprocess (Polynomials.to_dense_coefficients p) - let verify_shard t trusted_setup cm - {index = shard_index; share = shard_evaluations} proof = + let verify_shard t cm {index = shard_index; share = shard_evaluations} proof = let d_n = Domains.build ~log:t.evaluations_log in let domain = Domains.build ~log:t.evaluations_per_proof_log in verify + t cm - (trusted_setup.srs_g1, trusted_setup.kate_amortized_srs_g2_shards) + t.srs.kate_amortized_srs_g2_shards domain (Domains.get d_n shard_index, shard_evaluations) proof - let _prove_single trusted_setup p z = + let _prove_single t p z = let q, _ = Polynomials.( division_xn (p - constant (evaluate p z)) 1 (Scalar.negate z)) @@ -903,10 +781,10 @@ module Inner = struct commit' (module Bls12_381.G1) (Polynomials.to_dense_coefficients q) - trusted_setup.srs_g1 + t.srs.raw.srs_g1 - let _verify_single trusted_setup cm ~point ~evaluation proof = - let h_secret = Array.get trusted_setup.srs_g2 1 in + let _verify_single t cm ~point ~evaluation proof = + let h_secret = Array.get t.srs.raw.srs_g2 1 in Bls12_381.( Pairing.pairing_check [ @@ -915,30 +793,30 @@ module Inner = struct (proof, G2.(add h_secret (negate (mul (copy one) point)))); ]) - let prove_segment t trusted_setup p segment_index = + let prove_segment t p segment_index = if segment_index < 0 || segment_index >= t.nb_segments then Error `Segment_index_out_of_range else - let l = 1 lsl Z.(log2up (of_int t.segment_len)) in + let l = 1 lsl Z.(log2up (of_int t.segment_length)) in let wi = Domains.get t.domain_k segment_index in let quotient, _ = Polynomials.(division_xn p l Scalar.(negate (pow wi (Z.of_int l)))) in - commit trusted_setup quotient + Ok (commit t quotient) (* Parses the [slot_segment] to get the evaluations that it contains. The evaluation points are given by the [slot_segment_index]. *) - let verify_segment t trusted_setup cm - {index = slot_segment_index; content = slot_segment} proof = + let verify_segment t cm {index = slot_segment_index; content = slot_segment} + proof = if slot_segment_index < 0 || slot_segment_index >= t.nb_segments then Error `Segment_index_out_of_range else - let domain = Domains.build ~log:Z.(log2up (of_int t.segment_len)) in + let domain = Domains.build ~log:Z.(log2up (of_int t.segment_length)) in let slot_segment_evaluations = Array.init - (1 lsl Z.(log2up (of_int t.segment_len))) + (1 lsl Z.(log2up (of_int t.segment_length))) (function - | i when i < t.segment_len - 1 -> + | i when i < t.segment_length - 1 -> let dst = Bytes.create scalar_bytes_amount in Bytes.blit slot_segment @@ -947,7 +825,7 @@ module Inner = struct 0 scalar_bytes_amount ; Scalar.of_bytes_exn dst - | i when i = t.segment_len - 1 -> + | i when i = t.segment_length - 1 -> let dst = Bytes.create t.remaining_bytes in Bytes.blit slot_segment @@ -958,13 +836,42 @@ module Inner = struct Scalar.of_bytes_exn dst | _ -> Scalar.(copy zero)) in - verify - cm - (trusted_setup.srs_g1, trusted_setup.kate_amortized_srs_g2_segments) - domain - (Domains.get t.domain_k slot_segment_index, slot_segment_evaluations) - proof + Ok + (verify + t + cm + t.srs.kate_amortized_srs_g2_segments + domain + (Domains.get t.domain_k slot_segment_index, slot_segment_evaluations) + proof) end include Inner module Verifier = Inner + +module Internal_for_tests = struct + let initialisation_parameters_from_slot_size ~slot_size = + let size = slot_as_polynomial_length ~slot_size in + let secret = + Bls12_381.Fr.of_string + "20812168509434597367146703229805575690060615791308155437936410982393987532344" + in + let generator () = + Seq.unfold (fun (index, mul, g) -> + if index >= size then None + else + let next = mul g secret in + Some (g, (index + 1, mul, next))) + in + let srs_g1 = + let open Bls12_381.G1 in + generator () (0, mul, one) |> Array.of_seq + in + let srs_g2 = + let open Bls12_381.G2 in + generator () (0, mul, one) |> Array.of_seq + in + {srs_g1; srs_g2} + + let load_parameters parameters = initialisation_parameters := Some parameters +end diff --git a/src/lib_crypto_dal/dal_cryptobox.mli b/src/lib_crypto_dal/dal_cryptobox.mli index 31a0637a7627..48ce065de76a 100644 --- a/src/lib_crypto_dal/dal_cryptobox.mli +++ b/src/lib_crypto_dal/dal_cryptobox.mli @@ -29,9 +29,6 @@ open Dal_cryptobox_intf by this module. *) type t -(** A trusted setup. *) -type srs - (** Because of the shell/protocol separation, cryptographic primitives need to be splitted. An interface, called the {!module:Verifier} aims to be provided for the economic protocol. The other interface, @@ -54,12 +51,27 @@ type srs module Verifier : VERIFIER -include VERIFIER with type srs := srs and type t := t +include VERIFIER with type t := t + +(** The primitives exposed in this modules require some + preprocessing. This preprocessing generates data from an unknown + secret. For the security of those primtives, it is important that + the secret is unknown. *) +type initialisation_parameters -(** FIXME https://gitlab.com/tezos/tezos/-/issues/3390 +(** [initialisation_parameters_from_files ~g1_path ~g2_path] allows to + load initialisation_parameters from files [g1_path] and + [g2_path]. It is important that every time those primitives are + used, they are used with the very same initialisation + parameters. To ensure this property, an integrity check is run. - This is unsafe but can be used for testing. *) -val srs : t -> srs + This function can take several seconds to run. *) +val initialisation_parameters_from_files : + g1_path:string -> + g2_path:string -> + initialisation_parameters Error_monad.tzresult Lwt.t + +val load_parameters : initialisation_parameters -> unit Error_monad.tzresult module Commitment : sig include Dal_cryptobox_intf.COMMITMENT with type t = commitment @@ -108,10 +120,7 @@ val polynomial_to_bytes : t -> polynomial -> bytes Fails with [`Degree_exceeds_srs_length] if the degree of [p] exceeds the SRS size. *) -val commit : - srs -> - polynomial -> - (commitment, [> `Degree_exceeds_srs_length of string]) Result.t +val commit : t -> polynomial -> commitment (** A portion of the data represented by a polynomial. *) type share @@ -147,41 +156,46 @@ val shards_from_polynomial : t -> polynomial -> share IntMap.t (** A proof that a shard belongs to some commitment. *) type shard_proof -(** [verify_shard t srs commitment shard proof] allows to check +(** [verify_shard t commitment shard proof] allows to check whether [shard] is a portion of the data corresponding to the [commitment] using [proof]. The verification time is constant. The [srs] should be the same as the one used to produce the commitment. *) -val verify_shard : - t -> - srs -> - commitment -> - shard -> - shard_proof -> - (bool, [> `Degree_exceeds_srs_length of string]) result +val verify_shard : t -> commitment -> shard -> shard_proof -> bool -(** [prove_commitment srs polynomial] produces a proof that the +(** [prove_commitment polynomial] produces a proof that the slot represented by [polynomial] has its size bounded by the maximum slot size. *) -val prove_commitment : - srs -> - polynomial -> - (commitment_proof, [> `Degree_exceeds_srs_length of string]) result +val prove_commitment : t -> polynomial -> commitment_proof (** [prove_segment] produces a proof that the [n]th segment computed is part of a commitment. This segment corresponds to the original data and are split into [C.segment_size]. *) val prove_segment : t -> - srs -> polynomial -> int -> - ( segment_proof, - [> `Degree_exceeds_srs_length of string | `Segment_index_out_of_range] ) - result + (segment_proof, [> `Segment_index_out_of_range]) result (** [prove_shards] computes the proofs for all the [shards] that each [shard] is a valid piece of data associated to a polynomial and its commitment. Only the commitment is needed to check the proof. *) -val prove_shards : t -> srs -> polynomial -> shard_proof array +val prove_shards : t -> polynomial -> shard_proof array + +module Internal_for_tests : sig + (** The initialisation parameters can be too large for testing + purposes. This function creates an unsafe initialisation + parameters using some specified length (expected to be + positive). The running time of this function is linear with + respect to the size given. Order of magnitude can be around 1 + minute for a size of 1MiB. *) + val initialisation_parameters_from_slot_size : + slot_size:int -> initialisation_parameters + + (** Same as {!val:load_parameters} except it erase parameters if + they were already loaded. This is used to circumvent limitation + from test frameworks where tests with various parameters could be + run using the same binary. *) + val load_parameters : initialisation_parameters -> unit +end diff --git a/src/lib_crypto_dal/dal_cryptobox_intf.ml b/src/lib_crypto_dal/dal_cryptobox_intf.ml index 393406f170ac..6937559ec4f1 100644 --- a/src/lib_crypto_dal/dal_cryptobox_intf.ml +++ b/src/lib_crypto_dal/dal_cryptobox_intf.ml @@ -55,28 +55,7 @@ module type VERIFIER = sig slot_size:int -> segment_size:int -> number_of_shards:int -> - t - - (** A trusted setup. Namely Structured Reference String. - - Those are data necessary to make the cryptographic primitives - secured. In particular, to prevent an attacker from forging two - polynomials with the same commitment. *) - type srs - - (** [load_srs ()] loads a trusted [srs]. If the [srs] is already - loaded, it is given directly. Otherwise, the trusted [srs] is - read from two dedicated files. The function assumes those files - are located in some predetermined UNIX-compatible directories. - - The [srs] depends on the [slot_size] parameters. Loading the - first time an srs is consequently costly while the other times - would be cheap. - - We assume the [srs] won't change many times. The shell ensures - that a bounded and small number of [srs] can be loaded at the - same time. *) - val load_srs : t -> srs Error_monad.tzresult + (t, [> `Fail of string]) result (** Commitment to a polynomial. *) type commitment @@ -94,11 +73,7 @@ module type VERIFIER = sig [commitment] is valid. In particular, it checks that the size of the data committed via [commitment] does not exceed [C.slot_size]. The verification time is constant. *) - val verify_commitment : - srs -> - commitment -> - commitment_proof -> - (bool, [> `Degree_exceeds_srs_length of string]) Result.t + val verify_commitment : t -> commitment -> commitment_proof -> bool (** The original slot can be split into a list of segments of size [segment_size]. A segment is consequently encoded as a pair of an @@ -120,11 +95,8 @@ module type VERIFIER = sig Fails if the index of the segment is out of range. *) val verify_segment : t -> - srs -> commitment -> segment -> segment_proof -> - ( bool, - [> `Degree_exceeds_srs_length of string | `Segment_index_out_of_range] ) - Result.t + (bool, [> `Segment_index_out_of_range]) Result.t end diff --git a/src/lib_crypto_dal/test/test_dal_cryptobox.ml b/src/lib_crypto_dal/test/test_dal_cryptobox.ml index c200ee887389..8e0286b7c4c5 100644 --- a/src/lib_crypto_dal/test/test_dal_cryptobox.ml +++ b/src/lib_crypto_dal/test/test_dal_cryptobox.ml @@ -24,6 +24,7 @@ module Test = struct (* Encoding and decoding of Reed-Solomon codes on the erasure channel. *) let bench_DAL_crypto_params () = + let open Tezos_error_monad.Error_monad.Result_syntax in (* We take mainnet parameters we divide by [16] to speed up the test. *) let number_of_shards = 2048 / 16 in let slot_size = 1048576 / 16 in @@ -33,97 +34,79 @@ module Test = struct for i = 0 to (msg_size / 8) - 1 do Bytes.set_int64_le msg (i * 8) (Random.int64 Int64.max_int) done ; - let open Tezos_error_monad.Error_monad.Result_syntax in - List.iter + let parameters = + Dal_cryptobox.Internal_for_tests.initialisation_parameters_from_slot_size + ~slot_size + in + let () = Dal_cryptobox.Internal_for_tests.load_parameters parameters in + Tezos_lwt_result_stdlib.Lwtreslib.Bare.List.iter_e (fun redundancy_factor -> - let t = + let* t = Dal_cryptobox.make ~redundancy_factor ~slot_size ~segment_size ~number_of_shards in - let trusted_setup = - Dal_cryptobox.srs t - (*(`Files {srs_g1_file; srs_g2_file; logarithm_size = 21})*) + let* p = Dal_cryptobox.polynomial_from_slot t msg in + let cm = Dal_cryptobox.commit t p in + let* pi = Dal_cryptobox.prove_segment t p 1 in + let segment = Bytes.sub msg segment_size segment_size in + let* check = + Dal_cryptobox.verify_segment t cm {index = 1; content = segment} pi in - match - let* p = Dal_cryptobox.polynomial_from_slot t msg in - let* cm = Dal_cryptobox.commit trusted_setup p in - let* pi = Dal_cryptobox.prove_segment t trusted_setup p 1 in - let segment = Bytes.sub msg segment_size segment_size in - let* check = - Dal_cryptobox.verify_segment - t - trusted_setup - cm - {index = 1; content = segment} - pi - in - assert check ; - let enc_shards = Dal_cryptobox.shards_from_polynomial t p in - - (* Only take half of the buckets *) - let c_indices = - random_indices - (number_of_shards - 1) - (number_of_shards / redundancy_factor) - |> Array.of_list - in - - let c = - Dal_cryptobox.IntMap.filter - (fun i _ -> Array.mem i c_indices) - enc_shards - in - - let* dec = Dal_cryptobox.polynomial_from_shards t c in - assert ( - Bytes.compare - msg - (Bytes.sub - (Dal_cryptobox.polynomial_to_bytes t dec) - 0 - (min slot_size msg_size)) - = 0) ; - - let* comm = Dal_cryptobox.commit trusted_setup p in - - let shard_proofs = Dal_cryptobox.prove_shards t trusted_setup p in - match Dal_cryptobox.IntMap.find 0 enc_shards with - | None -> Ok () - | Some eval -> - let* check = - Dal_cryptobox.verify_shard - t - trusted_setup - comm - {index = 0; share = eval} - shard_proofs.(0) - in - assert check ; - - let* pi = Dal_cryptobox.prove_commitment trusted_setup p in - let* check = - Dal_cryptobox.verify_commitment trusted_setup comm pi - in - assert check ; - Ok () - (* let point = Scalar.random () in *) - (* let+ pi_slot = Dal_cryptobox.prove_single trusted_setup p point in - * - * assert ( - * Dal_cryptobox.verify_single - * trusted_setup - * comm - * ~point - * ~evaluation:(Dal_cryptobox.polynomial_evaluate p point) - * pi_slot) *) - with - | Ok () -> () - | Error _ -> assert false) + assert check ; + let enc_shards = Dal_cryptobox.shards_from_polynomial t p in + let c_indices = + random_indices + (number_of_shards - 1) + (number_of_shards / redundancy_factor) + |> Array.of_list + in + let c = + Dal_cryptobox.IntMap.filter + (fun i _ -> Array.mem i c_indices) + enc_shards + in + let* dec = Dal_cryptobox.polynomial_from_shards t c in + assert ( + Bytes.compare + msg + (Bytes.sub + (Dal_cryptobox.polynomial_to_bytes t dec) + 0 + (min slot_size msg_size)) + = 0) ; + let comm = Dal_cryptobox.commit t p in + let shard_proofs = Dal_cryptobox.prove_shards t p in + match Dal_cryptobox.IntMap.find 0 enc_shards with + | None -> Ok () + | Some eval -> + let check = + Dal_cryptobox.verify_shard + t + comm + {index = 0; share = eval} + shard_proofs.(0) + in + assert check ; + let pi = Dal_cryptobox.prove_commitment t p in + let check = Dal_cryptobox.verify_commitment t comm pi in + assert check ; + Ok () + (* let point = Scalar.random () in *) + (* let+ pi_slot = Dal_cryptobox.prove_single trusted_setup p point in + * + * assert ( + * Dal_cryptobox.verify_single + * trusted_setup + * comm + * ~point + * ~evaluation:(Dal_cryptobox.polynomial_evaluate p point) + * pi_slot) *)) [2] + |> fun x -> match x with Ok () -> () | Error _ -> assert false end let test = diff --git a/src/lib_protocol_environment/sigs/v7.ml b/src/lib_protocol_environment/sigs/v7.ml index 25b535dcb140..a0b6774e300e 100644 --- a/src/lib_protocol_environment/sigs/v7.ml +++ b/src/lib_protocol_environment/sigs/v7.ml @@ -11303,32 +11303,13 @@ end type t (** [make] precomputes the set of values needed by cryptographic primitives - defined in this module and store them in a value of type [t] *) + defined in this module and store them in a value of type [t] *) val make : redundancy_factor:int -> slot_size:int -> segment_size:int -> number_of_shards:int -> - t - -(** A trusted setup. Namely Structured Reference String. - - Those are data necessary to make the cryptographic primitives - secured. In particular, to prevent an attacker to forge two - polynomials with the same commitment. *) -type srs - -(** [load_srs ()] loads a trusted [srs]. If the [srs] is already - loaded, it is given directly. Otherwise, the trusted [srs] is read - from two dedicated files. The function assumes those files are - located in some predetermined directories UNIX-compatible. The - [srs] depends on the [slot_size] parameters. Loading the first time - an srs is consequently costly while the other times would be cheap. - - We assume the [srs] won't change many times. The shell ensures - that a bounded and small number of [srs] can be loaded at the same - time. *) -val load_srs : t -> srs Error_monad.shell_tzresult + (t, [> `Fail of string]) result (** Commitment to a polynomial. *) type commitment @@ -11362,11 +11343,7 @@ val commitment_proof_encoding : commitment_proof Data_encoding.t [commitment] is a valid [commitment]. In particular, it check that the size of the data committed via [commitment] do not exceed [C.slot_size]. The verification time is constant. *) -val verify_commitment : - srs -> - commitment -> - commitment_proof -> - (bool, [> `Degree_exceeds_srs_length of string]) Result.t +val verify_commitment : t -> commitment -> commitment_proof -> bool (** The original slot can be split into a list of segments of size [segment_size]. A segment is consequently encoded as a pair of an @@ -11388,7 +11365,6 @@ val segment_proof_encoding : segment_proof Data_encoding.t Fails if the index of the segment is out of range. *) val verify_segment : t -> - srs -> commitment -> segment -> segment_proof -> diff --git a/src/lib_protocol_environment/sigs/v7/dal.mli b/src/lib_protocol_environment/sigs/v7/dal.mli index aa58b208c14c..b1e2b016bd7f 100644 --- a/src/lib_protocol_environment/sigs/v7/dal.mli +++ b/src/lib_protocol_environment/sigs/v7/dal.mli @@ -27,32 +27,13 @@ type t (** [make] precomputes the set of values needed by cryptographic primitives - defined in this module and store them in a value of type [t] *) + defined in this module and store them in a value of type [t] *) val make : redundancy_factor:int -> slot_size:int -> segment_size:int -> number_of_shards:int -> - t - -(** A trusted setup. Namely Structured Reference String. - - Those are data necessary to make the cryptographic primitives - secured. In particular, to prevent an attacker to forge two - polynomials with the same commitment. *) -type srs - -(** [load_srs ()] loads a trusted [srs]. If the [srs] is already - loaded, it is given directly. Otherwise, the trusted [srs] is read - from two dedicated files. The function assumes those files are - located in some predetermined directories UNIX-compatible. The - [srs] depends on the [slot_size] parameters. Loading the first time - an srs is consequently costly while the other times would be cheap. - - We assume the [srs] won't change many times. The shell ensures - that a bounded and small number of [srs] can be loaded at the same - time. *) -val load_srs : t -> srs Error_monad.shell_tzresult + (t, [> `Fail of string]) result (** Commitment to a polynomial. *) type commitment @@ -86,11 +67,7 @@ val commitment_proof_encoding : commitment_proof Data_encoding.t [commitment] is a valid [commitment]. In particular, it check that the size of the data committed via [commitment] do not exceed [C.slot_size]. The verification time is constant. *) -val verify_commitment : - srs -> - commitment -> - commitment_proof -> - (bool, [> `Degree_exceeds_srs_length of string]) Result.t +val verify_commitment : t -> commitment -> commitment_proof -> bool (** The original slot can be split into a list of segments of size [segment_size]. A segment is consequently encoded as a pair of an @@ -112,7 +89,6 @@ val segment_proof_encoding : segment_proof Data_encoding.t Fails if the index of the segment is out of range. *) val verify_segment : t -> - srs -> commitment -> segment -> segment_proof -> diff --git a/tezt/lib_tezos/rollup.ml b/tezt/lib_tezos/rollup.ml index 2274ef57b47a..580a877fbccc 100644 --- a/tezt/lib_tezos/rollup.ml +++ b/tezt/lib_tezos/rollup.ml @@ -532,20 +532,24 @@ module Dal = struct module Cryptobox = Tezos_crypto_dal.Dal_cryptobox let make + ?(on_error = + fun msg -> Test.fail "Rollup.Dal.make: Unexpected error: %s" msg) Parameters.{redundancy_factor; number_of_shards; slot_size; segment_size} = - Cryptobox.make ~redundancy_factor ~slot_size ~segment_size ~number_of_shards - - let load_srs ?(unsafe = false) t = - if unsafe then Cryptobox.srs t - else - match Cryptobox.load_srs t with - | Ok srs -> srs - | Error err -> - Test.fail - "Rollup.Dal.load_srs failed: %a" - Tezos_base.TzPervasives.Error_monad.pp_print_trace - err + let initialisation_parameters = + Cryptobox.Internal_for_tests.initialisation_parameters_from_slot_size + ~slot_size + in + Cryptobox.Internal_for_tests.load_parameters initialisation_parameters ; + match + Cryptobox.make + ~redundancy_factor + ~slot_size + ~segment_size + ~number_of_shards + with + | Ok cryptobox -> cryptobox + | Error (`Fail msg) -> on_error msg module Commitment = struct let pad n message = @@ -563,15 +567,8 @@ module Dal = struct if padding_length > 0 then pad padding_length message else message in let slot = String.to_bytes padded_message in - (* FIXME - - Use a real srs here. *) - let srs = load_srs ~unsafe:true t in match Cryptobox.polynomial_from_slot t slot with - | Ok r -> ( - match Cryptobox.commit srs r with - | Ok r -> r - | Error (`Degree_exceeds_srs_length str) -> on_error str) + | Ok r -> Cryptobox.commit t r | Error (`Slot_wrong_size str) -> on_error str end end diff --git a/tezt/lib_tezos/rollup.mli b/tezt/lib_tezos/rollup.mli index db95d5c9fb1f..9e67f42924dd 100644 --- a/tezt/lib_tezos/rollup.mli +++ b/tezt/lib_tezos/rollup.mli @@ -230,7 +230,7 @@ module Dal : sig module Cryptobox = Tezos_crypto_dal.Dal_cryptobox - val make : Parameters.t -> Cryptobox.t + val make : ?on_error:(string -> Cryptobox.t) -> Parameters.t -> Cryptobox.t module Commitment : sig val dummy_commitment : diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index 08d007ce4ff5..127a5b6c8290 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -72,11 +72,31 @@ let setup ?commitment_period ?challenge_window ?dal_enable f ~protocol = Synchronisation_threshold 0; History_mode (Full None); No_bootstrap_peers; ] in - let* node, client = - Client.init_with_protocol ~parameter_file `Client ~protocol ~nodes_args () + let* client = Client.init_mockup ~parameter_file ~protocol () in + let* parameters = Rollup.Dal.Parameters.from_client client in + let cryptobox = Rollup.Dal.make parameters in + let node = Node.create nodes_args in + let* () = Node.config_init node [] in + Node.Config_file.update node (fun json -> + let value = + JSON.annotate + ~origin:"dal_initialisation" + (`O + [ + ("srs_size", `Float (float_of_int parameters.slot_size)); + ("activated", `Bool true); + ]) + in + let json = JSON.put ("dal", value) json in + json) ; + let* () = Node.run node [] in + let* () = Node.wait_for_ready node in + let* client = Client.init ~endpoint:(Node node) () in + let* () = + Client.activate_protocol_and_wait ~parameter_file ~protocol client in let bootstrap1_key = Constant.bootstrap1.public_key_hash in - f node client bootstrap1_key + f parameters cryptobox node client bootstrap1_key type test = {variant : string; tags : string list; description : string} @@ -113,7 +133,7 @@ let test_scenario ?commitment_period ?challenge_window ?dal_enable (Printf.sprintf "%s (%s)" description variant) (fun protocol -> setup ?commitment_period ?challenge_window ~protocol ?dal_enable - @@ fun node client -> + @@ fun _parameters _cryptobox node client -> ( with_fresh_rollup @@ fun sc_rollup_address sc_rollup_node _filename -> scenario protocol sc_rollup_node sc_rollup_address node client ) node @@ -198,8 +218,6 @@ let test_feature_flag _protocol _sc_rollup_node sc_rollup_address node client = Test.fail "Did not expect to find \"dal_slot_availibility\"" ; unit -open Tezt_tezos.Rollup.Dal - let publish_slot ~source ?fee ~index ~message parameters cryptobox node client = let level = Node.get_level node in let header = @@ -262,12 +280,8 @@ let test_slot_management_logic = ~tags:["dal"] ~supports:Protocol.(From_protocol (Protocol.number Alpha)) @@ fun protocol -> - let* parameter_file = Parameters.parameter_file protocol in - let* node, client = - Client.init_with_protocol ~parameter_file `Client ~protocol () - in - let* parameters = Rollup.Dal.Parameters.from_client client in - let cryptobox = Rollup.Dal.make parameters in + setup ~dal_enable:true ~protocol + @@ fun parameters cryptobox node client _bootstrap -> let* (`OpHash oph1) = publish_slot ~source:Constant.bootstrap1 -- GitLab