From cdfa47074247e9047035c41d7557e0cf850cd1e2 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Thu, 27 Feb 2025 14:35:57 +0100 Subject: [PATCH 1/4] DAL/Trap: fix typo in comment --- src/lib_crypto_dal/trap.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib_crypto_dal/trap.ml b/src/lib_crypto_dal/trap.ml index 1d67a7ec222c..2474a9ba7d9d 100644 --- a/src/lib_crypto_dal/trap.ml +++ b/src/lib_crypto_dal/trap.ml @@ -6,7 +6,7 @@ (*****************************************************************************) (* [share_is_trap pkh share ~traps_fraction] checks that - `hash(pkh . share) < trap_rate * 2^hash_size`, + `hash(pkh . share) < traps_fraction * 2^hash_size`, where the dot denotes concatenation and |v| the length of the bitstring v. *) let share_is_trap = let hash_size_bits = 8 * Tezos_crypto.Blake2B.size in -- GitLab From edf9fd2eee2f80c66d1eb9128ae62187e2cb22a4 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Thu, 27 Feb 2025 12:03:30 +0100 Subject: [PATCH 2/4] DAL/Tests: add Trap.share_is_trap to the benchmark --- tezt/tests/dal.ml | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index cddd2ed32577..97fc5609c71c 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -7288,10 +7288,14 @@ let dal_crypto_benchmark () = err | Ok x -> f x in + (* the defaults are the Rio parameters *) let number_of_shards = Cli.get_int ~default:512 "nb_shards" in let slot_size = Cli.get_int ~default:126_944 "slot_size" in let redundancy_factor = Cli.get_int ~default:8 "redundancy" in let page_size = Cli.get_int ~default:3967 "page_size" in + let traps_fraction = + Cli.get_float ~default:0.0005 "traps_fraction" |> Q.of_float + in let* () = let parameters = {number_of_shards; redundancy_factor; page_size; slot_size} @@ -7314,7 +7318,7 @@ let dal_crypto_benchmark () = () in Log.info "SRS loaded." ; - let*? config = + let*? () = Result.map_error (fun x -> `Fail @@ -7324,7 +7328,7 @@ let dal_crypto_benchmark () = x)) result in - Lwt.return config + unit in Profiler.record_f Profiler.main Debug (message, []) @@ fun () -> match make parameters with @@ -7367,7 +7371,7 @@ let dal_crypto_benchmark () = prove_shards dal ~precomputation ~polynomial |> Array.to_seq in let _polynomial = - Profiler.record_f Profiler.main Debug ("Reconstruct polynomial", []) + Profiler.record_f Profiler.main Debug ("reconstruct polynomial", []) @@ fun () -> polynomial_from_shards dal shards in let nb_pages = slot_size / page_size in @@ -7439,7 +7443,27 @@ let dal_crypto_benchmark () = in ()) in - () ; + let () = + let message = + sf "share_is_trap (number_of_shards:%d)" (Seq.length shards) + in + Profiler.record_f Profiler.main Debug (message, []) @@ fun () -> + shards + |> Seq.iter (fun {share; index = _} -> + let res = + Tezos_crypto_dal.Trap.share_is_trap + Tezos_crypto.Signature.Public_key_hash.zero + share + ~traps_fraction + in + match res with + | Ok _is_trap -> () + | Error err -> + Test.fail + "Unexpected error:@.%a@." + Data_encoding.Binary.pp_write_error + err) + in Lwt.return_unit in Profiler.close_and_unplug Profiler.main instance ; -- GitLab From 6cc6fe9ecb38e6938a1e76f6f125cd5e3d56ee93 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Thu, 27 Feb 2025 14:32:26 +0100 Subject: [PATCH 3/4] DAL: move helper functions from Tezt_tezos to Cryptobox --- src/lib_crypto_dal/cryptobox.ml | 42 +++++++++++++ src/lib_crypto_dal/cryptobox.mli | 32 ++++++++++ .../consensus/test_dal_entrapment.ml | 4 +- .../consensus/test_dal_entrapment.ml | 4 +- tezt/lib_tezos/dal_common.ml | 59 ++++--------------- tezt/lib_tezos/dal_common.mli | 20 ------- tezt/tests/dal.ml | 18 +++--- 7 files changed, 100 insertions(+), 79 deletions(-) diff --git a/src/lib_crypto_dal/cryptobox.ml b/src/lib_crypto_dal/cryptobox.ml index e441807ee824..6079b905cf9a 100644 --- a/src/lib_crypto_dal/cryptobox.ml +++ b/src/lib_crypto_dal/cryptobox.ml @@ -1100,6 +1100,24 @@ end include Inner module Verifier = Inner +let pp_error fmt = function + | `Fail message -> Format.fprintf fmt "Fail: %s" message + | `Not_enough_shards message -> + Format.fprintf fmt "Not enough shards: %s" message + | `Shard_index_out_of_range message -> + Format.fprintf fmt "Shard index out of range: %s" message + | `Invalid_shard_length message -> + Format.fprintf fmt "Invalid shard length: %s" message + | `Invalid_page -> Format.fprintf fmt "Invalid page" + | `Page_index_out_of_range -> Format.fprintf fmt "Page index out of range" + | `Invalid_degree_strictly_less_than_expected _ -> + Format.fprintf fmt "Invalid degree strictly less than expected" + | `Page_length_mismatch -> Format.fprintf fmt "Page length mismatch" + | `Slot_wrong_size message -> Format.fprintf fmt "Slot wrong size: %s" message + | `Prover_SRS_not_loaded -> Format.fprintf fmt "Prover SRS not loaded" + | `Shard_length_mismatch -> Format.fprintf fmt "Shard length mismatch" + | `Invalid_shard -> Format.fprintf fmt "Invalid shard" + module Internal_for_tests = struct let parameters_initialisation () = Prover @@ -1201,6 +1219,30 @@ module Internal_for_tests = struct | _ -> false let slot_as_polynomial_length = Parameters_check.slot_as_polynomial_length + + let generate_slot ~slot_size = + Bytes.init slot_size (fun _ -> + let x = Random.int 26 in + Char.chr (x + Char.code 'a')) + + let get_commitment_and_shards_with_proofs cryptobox ~slot = + let open Result_syntax in + let* precomputation = precompute_shards_proofs cryptobox in + let* polynomial = polynomial_from_slot cryptobox slot in + let shards = shards_from_polynomial cryptobox polynomial in + let shard_proofs = + prove_shards cryptobox ~precomputation ~polynomial |> Array.to_seq + in + let* commitment = commit cryptobox polynomial in + let* commitment_proof = prove_commitment cryptobox polynomial in + let shards = + Seq.fold_left2 + (fun seq shard proof -> Seq.cons (shard, proof) seq) + Seq.empty + shards + shard_proofs + in + return (commitment, commitment_proof, shards) end let init_prover_dal ~find_srs_files ?(srs_size_log2 = 21) ~fetch_trusted_setup diff --git a/src/lib_crypto_dal/cryptobox.mli b/src/lib_crypto_dal/cryptobox.mli index 7ac7b5f3ba7c..c4bb67a26db2 100644 --- a/src/lib_crypto_dal/cryptobox.mli +++ b/src/lib_crypto_dal/cryptobox.mli @@ -574,6 +574,22 @@ module Internal_for_tests : sig parameters -> (unit, [> `Fail of string]) result val slot_as_polynomial_length : slot_size:int -> page_size:int -> int + + (** Generates a random string (with chars from 'a' to 'z') of size + [slot_size]. *) + val generate_slot : slot_size:int -> bytes + + (** Given a slot, it returns the slot's commitment, its proof, and the shards + and their proof. *) + val get_commitment_and_shards_with_proofs : + t -> + slot:bytes -> + ( commitment * commitment_proof * (shard * shard_proof) Seq.t, + [> `Invalid_degree_strictly_less_than_expected of + (int, int) error_container + | `Prover_SRS_not_loaded + | `Slot_wrong_size of string ] ) + result end (** [init_prover_dal ~find_srs_files ?(srs_size_log2=21) ~fetch_trusted_setup ()] @@ -589,6 +605,22 @@ val init_prover_dal : unit -> unit Error_monad.tzresult Lwt.t +val pp_error : + Format.formatter -> + [ `Fail of string + | `Invalid_degree_strictly_less_than_expected of 'a + | `Invalid_page + | `Invalid_shard_length of string + | `Not_enough_shards of string + | `Page_index_out_of_range + | `Page_length_mismatch + | `Shard_index_out_of_range of string + | `Slot_wrong_size of string + | `Shard_length_mismatch + | `Prover_SRS_not_loaded + | `Invalid_shard ] -> + unit + (** node parameters for the DAL. *) module Config : sig type t = Dal_config.t = {activated : bool; bootstrap_peers : string list} diff --git a/src/proto_022_PsRiotum/lib_protocol/test/integration/consensus/test_dal_entrapment.ml b/src/proto_022_PsRiotum/lib_protocol/test/integration/consensus/test_dal_entrapment.ml index ed8dca03cd98..856f3f5879f8 100644 --- a/src/proto_022_PsRiotum/lib_protocol/test/integration/consensus/test_dal_entrapment.ml +++ b/src/proto_022_PsRiotum/lib_protocol/test/integration/consensus/test_dal_entrapment.ml @@ -50,7 +50,9 @@ let test_accusation_injection ?(initial_blocks_to_bake = 2) ?expect_failure | Some result -> result | None -> Log.info "generate slot and compute commitments and shards" ; - let slot = Tezt_tezos.Dal_common.Helpers.generate_slot ~slot_size in + let slot = + Tezos_crypto_dal.Cryptobox.Internal_for_tests.generate_slot ~slot_size + in let result = Tezt_tezos.Dal_common.Helpers.get_commitment_and_shards_with_proofs cryptobox diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_dal_entrapment.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_dal_entrapment.ml index d778a74ca385..94442ce6f165 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/test_dal_entrapment.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_dal_entrapment.ml @@ -115,7 +115,9 @@ let test_accusation_injection ?initial_blocks_to_bake ?expect_failure | Some result -> result | None -> Log.info "generate slot and compute commitments and shards" ; - let slot = Tezt_tezos.Dal_common.Helpers.generate_slot ~slot_size in + let slot = + Tezos_crypto_dal.Cryptobox.Internal_for_tests.generate_slot ~slot_size + in let result = Tezt_tezos.Dal_common.Helpers.get_commitment_and_shards_with_proofs cryptobox diff --git a/tezt/lib_tezos/dal_common.ml b/tezt/lib_tezos/dal_common.ml index 65697d48b31c..0463c3afeafb 100644 --- a/tezt/lib_tezos/dal_common.ml +++ b/tezt/lib_tezos/dal_common.ml @@ -634,25 +634,6 @@ module Helpers = struct assert (String.length slot = slot_size) ; slot - let pp_cryptobox_error fmt = function - | `Fail message -> Format.fprintf fmt "Fail: %s" message - | `Not_enough_shards message -> - Format.fprintf fmt "Not enough shards: %s" message - | `Shard_index_out_of_range message -> - Format.fprintf fmt "Shard index out of range: %s" message - | `Invalid_shard_length message -> - Format.fprintf fmt "Invalid shard length: %s" message - | `Invalid_page -> Format.fprintf fmt "Invalid page" - | `Page_index_out_of_range -> Format.fprintf fmt "Page index out of range" - | `Invalid_degree_strictly_less_than_expected _ -> - Format.fprintf fmt "Invalid degree strictly less than expected" - | `Page_length_mismatch -> Format.fprintf fmt "Page length mismatch" - | `Slot_wrong_size message -> - Format.fprintf fmt "Slot wrong size: %s" message - | `Prover_SRS_not_loaded -> Format.fprintf fmt "Prover SRS not loaded" - | `Shard_length_mismatch -> Format.fprintf fmt "Shard length mismatch" - | `Invalid_shard -> Format.fprintf fmt "Invalid shard" - let make_cryptobox ?(on_error = fun msg -> Test.fail "Dal_common.make: Unexpected error: %s" msg) @@ -686,34 +667,20 @@ module Helpers = struct e | Ok () -> unit - let generate_slot ~slot_size = - Bytes.init slot_size (fun _ -> - let x = Random.int 26 in - Char.chr (x + Char.code 'a')) - let get_commitment_and_shards_with_proofs cryptobox ~slot = - let open Cryptobox in - let ( let*? ) x f = - match x with - | Error err -> Test.fail "Unexpected error:@.%a@." pp_cryptobox_error err - | Ok x -> f x - in - let*? precomputation = precompute_shards_proofs cryptobox in - let*? polynomial = polynomial_from_slot cryptobox slot in - let shards = shards_from_polynomial cryptobox polynomial in - let shard_proofs = - prove_shards cryptobox ~precomputation ~polynomial |> Array.to_seq - in - let*? commitment = commit cryptobox polynomial in - let*? commitment_proof = prove_commitment cryptobox polynomial in - let shards = - Seq.fold_left2 - (fun seq shard proof -> Seq.cons (shard, proof) seq) - Seq.empty - shards - shard_proofs - in - (commitment, commitment_proof, shards) + let res = + Tezos_crypto_dal.Cryptobox.Internal_for_tests + .get_commitment_and_shards_with_proofs + cryptobox + ~slot + in + match res with + | Error err -> + Test.fail + "Unexpected error:@.%a@." + Tezos_crypto_dal.Cryptobox.pp_error + err + | Ok v -> v let publish_commitment ?dont_wait ?counter ?force ?source ?fee ?error ~index ~commitment ~proof client = diff --git a/tezt/lib_tezos/dal_common.mli b/tezt/lib_tezos/dal_common.mli index 32a2c5bf7dbe..9f4e4ca1708d 100644 --- a/tezt/lib_tezos/dal_common.mli +++ b/tezt/lib_tezos/dal_common.mli @@ -101,10 +101,6 @@ module Helpers : sig mode. *) val init_prover : ?__LOC__:string -> unit -> unit Lwt.t - (** Generates a random string (with chars from 'a' to 'z') of size - [slot_size]. *) - val generate_slot : slot_size:int -> bytes - val get_commitment_and_shards_with_proofs : Cryptobox.t -> slot:bytes -> @@ -148,22 +144,6 @@ module Helpers : sig slot -> string Lwt.t - val pp_cryptobox_error : - Format.formatter -> - [ `Fail of string - | `Invalid_degree_strictly_less_than_expected of 'a - | `Invalid_page - | `Invalid_shard_length of string - | `Not_enough_shards of string - | `Page_index_out_of_range - | `Page_length_mismatch - | `Shard_index_out_of_range of string - | `Slot_wrong_size of string - | `Shard_length_mismatch - | `Prover_SRS_not_loaded - | `Invalid_shard ] -> - unit - (** Wait for a connection event between [main_node] and [other_node]. The optional argument [other_peer_id] can be used to ignore the connection events which are not between these two diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index 97fc5609c71c..92ad56870e70 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -1063,7 +1063,7 @@ let simple_slot_producer ~slot_index ~slot_size ~from ~into dal_node l1_node (* This is the account used to sign injected slot headers on L1. *) let source = Constant.bootstrap2 in let slot = - Helpers.generate_slot ~slot_size + Cryptobox.Internal_for_tests.generate_slot ~slot_size |> Bytes.to_string |> Helpers.make_slot ~slot_size in @@ -7281,11 +7281,7 @@ let dal_crypto_benchmark () = Profiler.plug Profiler.main instance ; let ( let*? ) x f = match x with - | Error err -> - Test.fail - "Unexpected error:@.%a@." - Dal_common.Helpers.pp_cryptobox_error - err + | Error err -> Test.fail "Unexpected error:@.%a@." Cryptobox.pp_error err | Ok x -> f x in (* the defaults are the Rio parameters *) @@ -7347,7 +7343,7 @@ let dal_crypto_benchmark () = in let slot = Profiler.record_f Profiler.main Debug ("slot generation", []) - @@ fun () -> Helpers.generate_slot ~slot_size + @@ fun () -> Cryptobox.Internal_for_tests.generate_slot ~slot_size in let*? polynomial = Profiler.record_f Profiler.main Debug ("polynomial from slot", []) @@ -8699,7 +8695,7 @@ let test_inject_accusation _protocol dal_parameters cryptobox node client let slot_size = dal_parameters.Dal.Parameters.cryptobox.slot_size in let number_of_slots = dal_parameters.number_of_slots in let lag = dal_parameters.attestation_lag in - let slot = Helpers.generate_slot ~slot_size in + let slot = Cryptobox.Internal_for_tests.generate_slot ~slot_size in let commitment, proof, shards_with_proofs = Helpers.get_commitment_and_shards_with_proofs cryptobox ~slot in @@ -9033,7 +9029,7 @@ let test_duplicate_denunciations _protocol dal_parameters cryptobox node client let* current_level = Node.get_level node in let* shards_with_proofs = let slot_size = dal_parameters.Dal.Parameters.cryptobox.slot_size in - let slot = Helpers.generate_slot ~slot_size in + let slot = Cryptobox.Internal_for_tests.generate_slot ~slot_size in let commitment, proof, shards_with_proofs = Helpers.get_commitment_and_shards_with_proofs cryptobox ~slot in @@ -9164,7 +9160,7 @@ let test_denunciation_next_cycle _protocol dal_parameters cryptobox node client let* current_level = Node.get_level node in Log.info "Publish first commitment at level %d" current_level ; let slot_size = dal_parameters.Dal.Parameters.cryptobox.slot_size in - let slot = Helpers.generate_slot ~slot_size in + let slot = Cryptobox.Internal_for_tests.generate_slot ~slot_size in let commitment, proof, shards_with_proofs = Helpers.get_commitment_and_shards_with_proofs cryptobox ~slot in @@ -9183,7 +9179,7 @@ let test_denunciation_next_cycle _protocol dal_parameters cryptobox node client let* current_level = Node.get_level node in Log.info "Publish second commitment at level %d" current_level ; let slot_size = dal_parameters.Dal.Parameters.cryptobox.slot_size in - let slot = Helpers.generate_slot ~slot_size in + let slot = Cryptobox.Internal_for_tests.generate_slot ~slot_size in let commitment, proof, shards_with_proofs = Helpers.get_commitment_and_shards_with_proofs cryptobox ~slot in -- GitLab From 2c5173e14aa01d55bf63a69955e4497bc205f47a Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Thu, 27 Feb 2025 14:38:12 +0100 Subject: [PATCH 4/4] DAL/Tests: add test for Trap.share_is_trap --- manifest/product_octez.ml | 5 +- src/lib_crypto_dal/test/dune | 9 +- src/lib_crypto_dal/test/test_dal_cryptobox.ml | 2 +- src/lib_crypto_dal/test/test_trap.ml | 180 ++++++++++++++++++ 4 files changed, 190 insertions(+), 6 deletions(-) create mode 100644 src/lib_crypto_dal/test/test_trap.ml diff --git a/manifest/product_octez.ml b/manifest/product_octez.ml index 238513cf02e9..e28582027541 100644 --- a/manifest/product_octez.ml +++ b/manifest/product_octez.ml @@ -2067,7 +2067,7 @@ let octez_crypto_dal = let _octez_crypto_dal_tests = tezt - ["test_dal_cryptobox"] + ["test_dal_cryptobox"; "test_trap"] ~path:"src/lib_crypto_dal/test" ~opam:"octez-libs" ~dep_files:["srs_zcash_g1_5"; "srs_zcash_g2_5"] @@ -2081,7 +2081,8 @@ let _octez_crypto_dal_tests = alcotezt; qcheck_alcotest; octez_bls12_381_polynomial; - octez_test_helpers; + octez_base_test_helpers |> open_; + octez_base |> open_ ~m:"TzPervasives"; ] let ppx_brassaia = diff --git a/src/lib_crypto_dal/test/dune b/src/lib_crypto_dal/test/dune index 6b7392fd7703..a60589c03fcb 100644 --- a/src/lib_crypto_dal/test/dune +++ b/src/lib_crypto_dal/test/dune @@ -15,7 +15,8 @@ octez-alcotezt qcheck-alcotest octez-libs.bls12-381-polynomial - octez-libs.test-helpers) + octez-libs.base-test-helpers + octez-libs.base) (library_flags (:standard -linkall)) (flags (:standard) @@ -26,8 +27,10 @@ -open Tezos_crypto_dal_octez_dal_config -open Tezos_error_monad -open Data_encoding - -open Octez_alcotezt) - (modules test_dal_cryptobox)) + -open Octez_alcotezt + -open Tezos_base_test_helpers + -open Tezos_base.TzPervasives) + (modules test_dal_cryptobox test_trap)) (executable (name main) diff --git a/src/lib_crypto_dal/test/test_dal_cryptobox.ml b/src/lib_crypto_dal/test/test_dal_cryptobox.ml index 59f8374050ab..dc570ebc6275 100644 --- a/src/lib_crypto_dal/test/test_dal_cryptobox.ml +++ b/src/lib_crypto_dal/test/test_dal_cryptobox.ml @@ -335,7 +335,7 @@ module Test = struct t in let random_shards = - Seq.take shards_amount shards + Stdlib.Seq.take shards_amount shards |> Seq.map (fun ({share; _} : Cryptobox.shard) : Cryptobox.shard -> { index = out_of_range ~min:0 ~max:params.number_of_shards; diff --git a/src/lib_crypto_dal/test/test_trap.ml b/src/lib_crypto_dal/test/test_trap.ml new file mode 100644 index 000000000000..2588e1d36bf8 --- /dev/null +++ b/src/lib_crypto_dal/test/test_trap.ml @@ -0,0 +1,180 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2025 Nomadic Labs, *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Lib_crypto_dal Test_dal_cryptobox + Invocation: dune exec src/lib_crypto_dal/test/main.exe -- --file test_trap.ml + Subject: Tests the Trap module +*) + +let get_commitment_and_shards_with_proofs cryptobox ~slot = + let res = + Cryptobox.Internal_for_tests.get_commitment_and_shards_with_proofs + cryptobox + ~slot + in + match res with + | Error err -> + Test.fail ~__LOC__ "Unexpected error:@.%a@." Cryptobox.pp_error err + | Ok v -> v + +(* The Rio parameters; see src/proto_022_PsRiotum/lib_parameters/default_parameters.ml *) +let slot_size = 126_944 + +let number_of_shards = 512 + +let parameters = + { + Cryptobox.page_size = 3967; + slot_size; + redundancy_factor = 8; + number_of_shards; + } + +let traps_fraction = Q.(1 // 2_000) + +let setup () = + let open Lwt_result_syntax in + Log.info "Loading SRS..." ; + let* () = + Cryptobox.init_prover_dal + ~find_srs_files:Tezos_base.Dal_srs.find_trusted_setup_files + ~fetch_trusted_setup:false + () + in + assert (Cryptobox.Internal_for_tests.ensure_validity parameters) ; + let*? cryptobox = + let res = Cryptobox.make parameters in + match res with Ok v -> Ok v | Error (`Fail str) -> error_with "%s" str + in + Log.info "The cryptobox is available" ; + return cryptobox + +let test_share_is_trap_stats () = + let open Lwt_result_syntax in + let* cryptobox = setup () in + + (* some real public key hashes *) + let pkhs = + [ + "tz1irJKkXS2DBWkU1NnmFQx1c1L7pbGg4yhk"; + "tz1aRoaRhSpRYvFdyvgWLL6TGyRoGF51wDjM"; + "tz3cqThj23Feu55KDynm7Vg81mCMpWDgzQZq"; + "tz3Zhs2dygr55yHyQyKjntAtY9bgfhLZ4Xj1"; + "tz1N7fL6KvRzD5Umy7yeX5uBa5wFsC5veuN2"; + ] + in + let*? pkhs = + List.map_e Tezos_crypto.Signature.Public_key_hash.of_b58check pkhs + in + + (* The number of shards to be generated and used is such that there should be + 100 traps in total. *) + let num_samples = Q.(of_int 100 * (one / traps_fraction) |> to_int) in + let number_of_slots = 1 + (num_samples / number_of_shards) in + let total_shards = number_of_slots * number_of_shards in + + Log.info + "Check for traps_fraction %s and %d shards (%d slots) " + (Q.to_string traps_fraction) + total_shards + number_of_slots ; + + (* Generate random slots and count traps per pkh. *) + let num_traps = Array.make (List.length pkhs) 0 in + let count_traps pkh shards ~traps_fraction = + Seq.filter + (fun (Cryptobox.{share; _}, _proof) -> + match Trap.share_is_trap pkh share ~traps_fraction with + | Ok true -> true + | _ -> false) + shards + |> Seq.length + in + let rec iter_on_slots slot_index = + let () = Log.debug " slot %d" slot_index in + let slot = Cryptobox.Internal_for_tests.generate_slot ~slot_size in + let _commitment, _proof, shards = + get_commitment_and_shards_with_proofs cryptobox ~slot + in + List.iteri + (fun pkh_index pkh -> + num_traps.(pkh_index) <- + num_traps.(pkh_index) + count_traps pkh shards ~traps_fraction) + pkhs ; + if slot_index >= number_of_slots then + (* Return the last slot's shards, for checking the edge cases. *) + shards + else iter_on_slots (slot_index + 1) + in + let shards = iter_on_slots 1 in + + (* First check for the edge cases when the [traps_fraction] is 0 or 1. *) + let num_traps_0 = + count_traps (Stdlib.List.hd pkhs) shards ~traps_fraction:Q.zero + in + Check.( + (num_traps_0 = 0) int ~__LOC__ ~error_msg:"Expected zero traps, got %L") ; + let num_traps_1 = + count_traps (Stdlib.List.hd pkhs) shards ~traps_fraction:Q.one + in + Check.( + (num_traps_1 = number_of_shards) + int + ~__LOC__ + ~error_msg:"Expected %R traps, got %L") ; + + (* Now do the checks for the real [traps_fraction]. *) + let expected_traps = Q.(traps_fraction * of_int total_shards |> to_int) in + (* We allow a deviation of 10% from the expected number of traps. *) + let tolerance = + Q.(traps_fraction * of_int total_shards * (10 // 100) |> to_int) + in + Log.info + "expected number of traps = %d, tolerated difference = %d" + expected_traps + tolerance ; + List.iteri + (fun pkh_index pkh -> + Log.info + "number of traps for %a: %d" + Tezos_crypto.Signature.Public_key_hash.pp + pkh + num_traps.(pkh_index) ; + if abs (expected_traps - num_traps.(pkh_index)) > tolerance then + Test.fail + "Unexpected traps count for %a and traps fraction %s: expected %d \ + but got %d (tolerance: %d)" + Tezos_crypto.Signature.Public_key_hash.pp + pkh + (Q.to_string traps_fraction) + expected_traps + num_traps.(pkh_index) + tolerance) + pkhs ; + return_unit + +let tests = + [Tztest.tztest "share_is_trap statistics" `Slow test_share_is_trap_stats] + +let () = + (* Seed for deterministic pseudo-randomness: + If the environment variable RANDOM_SEED is set, then its value is used as + as seed. Otherwise, a random seed is used. + WARNING: using [Random.self_init] elsewhere in the tests breaks the determinism. + *) + let seed = + match Sys.getenv_opt "RANDOM_SEED" with + | None -> + Random.self_init () ; + Random.int 1073741823 + | Some v -> int_of_string v + in + Random.init seed ; + Alcotest_lwt.run ~__FILE__ "DAL.Trap" [("share_is_trap", tests)] + |> Lwt_main.run -- GitLab