diff --git a/src/lib_distributed_plonk/plonk-distribution/main_protocol.ml b/src/lib_distributed_plonk/plonk-distribution/main_protocol.ml index 4a54154608457da8d796c7aec3bd9193f506774a..ed990f2575bc561ade40671bf0180eaa6f8b7a68 100644 --- a/src/lib_distributed_plonk/plonk-distribution/main_protocol.ml +++ b/src/lib_distributed_plonk/plonk-distribution/main_protocol.ml @@ -83,27 +83,32 @@ module type S = sig Evaluations.t SMap.t list SMap.t -> Poly.t SMap.t - val batched_wires_poly_of_batched_wires : + val build_f_map_perm : prover_public_parameters -> - Evaluations.t SMap.t -> - Scalar.t * Poly.t SMap.t option list -> + gate_randomness -> + Evaluations.t SMap.t SMap.t -> Poly.t SMap.t - val build_batched_wires_values : + (* builds the range check proof polynomials *) + val build_f_map_rc_1 : + ?shifts_map:(int * int) SMap.t -> + prover_public_parameters -> gate_randomness -> Evaluations.t SMap.t list SMap.t -> - Evaluations.t SMap.t SMap.t + Evaluations.t SMap.t SMap.t -> + Poly.t SMap.t * Evaluations.t SMap.t SMap.t - val build_f_map_perm : + (* builds the range check’s permutation proof polynomials *) + val build_f_map_rc_2 : prover_public_parameters -> gate_randomness -> Evaluations.t SMap.t SMap.t -> Poly.t SMap.t - val build_perm_identities : + val build_perm_rc2_identities : prover_public_parameters -> gate_randomness -> prover_identities - val build_gates_plook_rc_identities : + val build_gates_plook_rc1_identities : ?shifts_map:(int * int) SMap.t -> prover_public_parameters -> gate_randomness -> @@ -287,13 +292,22 @@ module Common (PP : Polynomial_protocol.S) = struct let commit_to_plook_rc pp shifts_map transcript f_wires_list_map = let rd, _transcript = build_gates_randomness transcript in - let batched_wires_map = build_batched_wires_values rd f_wires_list_map in + let batched_wires_map = + Perm.Shared_argument.build_batched_wires_values + ~delta:rd.delta + ~wires:f_wires_list_map + in (* ******************************************* *) let f_map_plook = build_f_map_plook ~shifts_map pp rd f_wires_list_map in - let f_map_rc = - Prover.build_f_map_range_checks ~shifts_map pp rd f_wires_list_map - in - let f_map = SMap.union_disjoint f_map_plook f_map_rc in + (* FIXME https://gitlab.com/nomadic-labs/cryptography/privacy-team/-/issues/222 + Handle multiproofs + *) + (* let f_map_rc, batched_wires_map = + Prover.build_f_map_range_checks ~shifts_map pp rd f_wires_list_map + batched_wires_map + in + let f_map = SMap.union_disjoint f_map_plook f_map_rc in *) + let f_map = f_map_plook in (* commit to the plookup polynomials *) let cmt, prover_aux = (* FIXME: implement Plookup *) @@ -339,7 +353,7 @@ module Common (PP : Polynomial_protocol.S) = struct SMap.map (fun batched_witness -> (* we apply an IFFT on the batched witness *) - batched_wires_poly_of_batched_wires + Perm.Shared_argument.batched_wires_poly_of_batched_wires pp batched_witness (Scalar.zero, [])) @@ -380,13 +394,15 @@ module Common (PP : Polynomial_protocol.S) = struct let evaluated_perm_ids = let evaluations = let batched_wires_polys = - build_batched_witness_polys_bis pp batched_wires_map + build_batched_witness_polys_bis + (pp.common_pp.zk, pp.common_pp.n, pp.common_pp.domain) + batched_wires_map in build_evaluations pp (SMap.union_disjoint f_map_perm batched_wires_polys) in - (build_perm_identities pp randomness) evaluations + (build_perm_rc2_identities pp randomness) evaluations in let cmt = Commitment.commit pp.common_pp.pp_public_parameters f_map_perm in diff --git a/src/lib_distributed_plonk/worker.ml b/src/lib_distributed_plonk/worker.ml index ebddabf4b8fc5d916261cbd16a1b7508293202f8..77117e68ae0ad42290ed32b99a131b31e251b671 100644 --- a/src/lib_distributed_plonk/worker.ml +++ b/src/lib_distributed_plonk/worker.ml @@ -95,7 +95,7 @@ module Make (Main : Plonk_for_distribution.Main_protocol.S) : S = struct Prover.build_evaluations pp (SMap.union_disjoint all_f_wires f_map) in let identities = - Prover.build_gates_plook_rc_identities + Prover.build_gates_plook_rc1_identities ~shifts_map pp { diff --git a/src/lib_plompiler/csir.ml b/src/lib_plompiler/csir.ml index 330596396d4f45787021c45e6f21a2734656bbc1..5d07eb6be1a4183ce50236c59542a5928de19e8c 100644 --- a/src/lib_plompiler/csir.ml +++ b/src/lib_plompiler/csir.ml @@ -47,12 +47,11 @@ module Scalar = struct let mone = negate one - let string_of_scalar x = - if eq x (of_string "-1") then "-1" - else if eq x (of_string "-2") then "-2" - else - let s = to_string x in - if String.length s > 3 then "h" ^ string_of_int (Z.hash (to_z x)) else s + let string_of_scalar s = + if String.length (to_string s) < 10 then to_string s + else if String.length (to_string (negate s)) < 10 then + "-" ^ to_string (negate s) + else "H" ^ (to_z s |> Z.hash |> string_of_int) let equal a b = Bytes.equal (to_bytes a) (to_bytes b) diff --git a/src/lib_plonk/bls.ml b/src/lib_plonk/bls.ml index 3804c4481ee5b64ffde16e5c7a82d793d8845ad9..3fdda80db606205ba699f7a0b113ffd5225d3914 100644 --- a/src/lib_plonk/bls.ml +++ b/src/lib_plonk/bls.ml @@ -1,10 +1,4 @@ -module Scalar = struct - include Bls12_381.Fr - - let t : t Repr.t = - Repr.(map (bytes_of (`Fixed size_in_bytes)) of_bytes_exn to_bytes) -end - +module Scalar = Plompiler.Csir.Scalar module Scalar_map = Map.Make (Scalar) module Poly = Bls12_381_polynomial.Polynomial module Domain = Bls12_381_polynomial.Domain diff --git a/src/lib_plonk/custom_gates.ml b/src/lib_plonk/custom_gates.ml index a522a1694c995ddd28f4438d4f2d474bee1143bb..a0250a8bc29655806cd164a907b6ceab4db033d6 100644 --- a/src/lib_plonk/custom_gates.ml +++ b/src/lib_plonk/custom_gates.ml @@ -63,10 +63,9 @@ module type S = sig val aggregate_blinds : gates:'a SMap.t -> int SMap.t val aggregate_prover_identities : - ?circuit_name:string -> + ?circuit_prefix:(string -> string) -> input_coms_size:int -> - proof_idx:int -> - nb_proofs:int -> + proof_prefix:(string -> string) -> gates:'a SMap.t -> public_inputs:Scalar.t array -> domain:Domain.t -> @@ -74,10 +73,9 @@ module type S = sig prover_identities val aggregate_verifier_identities : - ?circuit_name:string -> + ?circuit_prefix:(string -> string) -> input_com_sizes:int list -> - proof_idx:int -> - nb_proofs:int -> + proof_prefix:(string -> string) -> gates:'a SMap.t -> public_inputs:Scalar.t array -> generator:Scalar.t -> @@ -220,7 +218,7 @@ module Aggregator = struct let sum_array a = Array.fold_left ( + ) 0 a in SMap.map sum_array blinds_array - let filter_evaluations ~evaluations ~prefix ~prefix_common gates = + let filter_evaluations ~evaluations ~prefix ~circuit_prefix gates = let get_eval = Evaluations.find_evaluation evaluations in let base = List.fold_left @@ -256,19 +254,19 @@ module Aggregator = struct (* Adding advice *) let acc = List.init (get_nb_advs gate) (fun i -> - prefix_common qadv_label ^ string_of_int i) + circuit_prefix qadv_label ^ string_of_int i) |> List.fold_left (fun acc2 adv_i -> SMap.add adv_i (get_eval adv_i) acc2) acc in (* Adding selector *) - let gate = prefix_common gate in - if String.starts_with ~prefix:(prefix_common "qpub") gate then acc + let gate = circuit_prefix gate in + if String.starts_with ~prefix:(circuit_prefix "qpub") gate then acc else SMap.add gate (get_eval gate) acc) base gates - let filter_answers ~answers ~prefix ~prefix_common gates = + let filter_answers ~answers ~prefix ~circuit_prefix gates = let x, gx = (string_of_eval_point X, string_of_eval_point GX) in let get_x, get_gx = (get_answer answers X, get_answer answers GX) in let add_mapmap k' k v mm = @@ -307,107 +305,96 @@ module Aggregator = struct (* Adding advice *) let acc = List.init (get_nb_advs gate) (fun i -> - prefix_common qadv_label ^ string_of_int i) + circuit_prefix qadv_label ^ string_of_int i) |> List.fold_left (fun acc2 adv_i -> add_x adv_i (get_x adv_i) acc2) acc in (* Adding selector *) - let gate = prefix_common gate in - if String.starts_with ~prefix:(prefix_common "qpub") gate then acc + let gate = circuit_prefix gate in + if String.starts_with ~prefix:(circuit_prefix "qpub") gate then acc else add_x gate (get_x gate) acc) base gates - let aggregate_prover_identities ?(circuit_name = "") ~input_coms_size - ~proof_idx ~nb_proofs ~gates ~public_inputs ~domain () : prover_identities + let aggregate_prover_identities ?(circuit_prefix = Fun.id) ~input_coms_size + ~proof_prefix:prefix ~gates ~public_inputs ~domain () : prover_identities = - let prefix_common = SMap.Aggregation.add_prefix circuit_name in - let prefix = - SMap.Aggregation.add_prefix ~n:nb_proofs ~i:proof_idx circuit_name + fun evaluations -> + let size_eval = Evaluations.size_evaluations evaluations in + (* Sort and filter gates according to nb of tmp buffers *) + let gates = + List.sort + (fun gate1 gate2 -> + Int.compare (get_nb_buffers gate1) (get_nb_buffers gate2)) + (filter_gates gates |> SMap.keys) in - fun evaluations -> - let size_eval = Evaluations.size_evaluations evaluations in - (* Sort and filter gates according to nb of tmp buffers *) - let gates = - List.sort - (fun gate1 gate2 -> - Int.compare (get_nb_buffers gate1) (get_nb_buffers gate2)) - (filter_gates gates |> SMap.keys) - in - (* Creating tmp buffers for prover identities *) - let nb_min_buffers = - match gates with - | [] -> 0 - | hd_gates :: _ -> max 1 (get_nb_buffers hd_gates) - in - tmp_buffers := - Array.init nb_min_buffers (fun _ -> Evaluations.create size_eval) ; - (* Filter evaluations *) - let evaluations = - filter_evaluations ~evaluations ~prefix ~prefix_common gates - in - (* Except for the arithmetic gates, - all gates correspond to distinct identities. *) - let init_ids = - let arith_acc_evaluation = Evaluations.create size_eval in - SMap.singleton (prefix @@ arith ^ ".0") arith_acc_evaluation - in - let union key e1 e2 = - assert (key = prefix @@ arith ^ ".0") ; - Some (Evaluations.add ~res:e1 e1 e2) - in - let public = {public_inputs; input_coms_size} in - List.fold_left - (fun accumulated_ids gate -> - SMap.union - union - accumulated_ids - (get_prover_identities - gate - ~prefix_common - ~prefix - ~public - ~domain - evaluations)) - init_ids - gates - - let aggregate_verifier_identities ?(circuit_name = "") ~input_com_sizes - ~proof_idx ~nb_proofs ~gates ~public_inputs ~generator ~size_domain () : + (* Creating tmp buffers for prover identities *) + let nb_min_buffers = + match gates with + | [] -> 0 + | hd_gates :: _ -> max 1 (get_nb_buffers hd_gates) + in + tmp_buffers := + Array.init nb_min_buffers (fun _ -> Evaluations.create size_eval) ; + (* Filter evaluations *) + let evaluations = + filter_evaluations ~evaluations ~prefix ~circuit_prefix gates + in + (* Except for the arithmetic gates, + all gates correspond to distinct identities. *) + let init_ids = + let arith_acc_evaluation = Evaluations.create size_eval in + SMap.singleton (prefix @@ arith ^ ".0") arith_acc_evaluation + in + let union key e1 e2 = + assert (key = prefix @@ arith ^ ".0") ; + Some (Evaluations.add ~res:e1 e1 e2) + in + let public = {public_inputs; input_coms_size} in + List.fold_left + (fun accumulated_ids gate -> + SMap.union + union + accumulated_ids + (get_prover_identities + gate + ~prefix_common:circuit_prefix + ~prefix + ~public + ~domain + evaluations)) + init_ids + gates + + let aggregate_verifier_identities ?(circuit_prefix = Fun.id) ~input_com_sizes + ~proof_prefix:prefix ~gates ~public_inputs ~generator ~size_domain () : verifier_identities = - let prefix_common = SMap.Aggregation.add_prefix circuit_name in - let prefix = - SMap.Aggregation.add_prefix ~n:nb_proofs ~i:proof_idx circuit_name + fun x answers -> + let gates = filter_gates gates |> SMap.keys in + let answers = filter_answers ~answers ~prefix ~circuit_prefix gates in + let arith_id = SMap.singleton (prefix @@ arith ^ ".0") Scalar.zero in + let union key s1 s2 = + assert (key = prefix @@ arith ^ ".0") ; + Some (Scalar.add s1 s2) in - fun x answers -> - let gates = filter_gates gates |> SMap.keys in - let answers = filter_answers ~answers ~prefix ~prefix_common gates in - let arith_id = SMap.singleton (prefix @@ arith ^ ".0") Scalar.zero in - let union key s1 s2 = - assert (key = prefix @@ arith ^ ".0") ; - Some (Scalar.add s1 s2) - in - let public = - { - public_inputs; - input_coms_size = List.fold_left ( + ) 0 input_com_sizes; - } - in - List.fold_left - (fun accumulated_ids gate -> - let gate_ids = - get_verifier_identities - gate - ~prefix_common - ~prefix - ~public - ~generator - ~size_domain - in - SMap.union union accumulated_ids (gate_ids x answers)) - arith_id - gates + let public = + {public_inputs; input_coms_size = List.fold_left ( + ) 0 input_com_sizes} + in + List.fold_left + (fun accumulated_ids gate -> + let gate_ids = + get_verifier_identities + gate + ~prefix_common:circuit_prefix + ~prefix + ~public + ~generator + ~size_domain + in + SMap.union union accumulated_ids (gate_ids x answers)) + arith_id + gates let aggregate_polynomials_degree ~gates = SMap.fold diff --git a/src/lib_plonk/main_protocol.ml b/src/lib_plonk/main_protocol.ml index f1e1283efa7df3e8f20db67d44dde251b36ca2d0..35fac6fcc166fac661f7c4ffb7fc26812a36b9f3 100644 --- a/src/lib_plonk/main_protocol.ml +++ b/src/lib_plonk/main_protocol.ml @@ -370,96 +370,6 @@ module Make_impl (PP : Polynomial_protocol.S) = struct in (wires_list_map, f_wires, f_blinds, all_f_wires, cm_wires, cm_aux_wires) - (* The shared permutation argument consists of leveraging the fact that - all proofs of the same circuit type share the same permutation - for ensuring the copy-satisfiability. - This allows us to run a single permutation argument on a linear - combination of the wire polynomials of all same-circuit proofs. - Namely, let a_i(X), b_i(X), c_i(X) be the wire polynomials of the - i-th proof. Let delta be some scalar sampled after (and based on) - a commitment to all a_i, b_i, c_i and consider batched polynomials: - A(X) := \sum_i delta^{i-1} a_i(X) - B(X) := \sum_i delta^{i-1} b_i(X) - C(X) := \sum_i delta^{i-1} c_i(X) - We will perform a single permutation argument for A, B and C. *) - let build_batched_wires_values {delta; _} wires_list_map = - let agg_map = - SMap.of_list - ((List.map (fun i -> (i, []))) - (wire_names Plompiler.Csir.nb_wires_arch)) - in - SMap.map - (fun l -> - List.fold_left - (fun acc wires -> - (SMap.mapi (fun k v -> SMap.find k wires :: v)) acc) - agg_map - (List.rev l) - |> SMap.map (fun ws_list -> - Evaluations.linear_with_powers ws_list delta)) - wires_list_map - |> SMap.(map (update_keys String.capitalize_ascii)) - - (* For each circuit, interpolates the batched wires A, B, C from the - batched witness *) - let batched_wires_poly_of_batched_wires {common_pp; _} batched_wires - (delta, f_blinds) = - let batched_polys = - SMap.map - (fun w -> Evaluations.interpolation_fft common_pp.domain w) - batched_wires - in - if not common_pp.zk then batched_polys - else - (* delta is only used to batched the blinds, the polys are computed - from a witness batched with delta already *) - let batched_blinds = - let f_blinds = List.map (fun b -> Option.get b) f_blinds in - SMap.map_list_to_list_map f_blinds - |> SMap.map (fun p -> Poly.linear_with_powers p delta) - in - SMap.mapi - (fun name f -> - let b = SMap.find name batched_blinds in - Poly.(f + mul_xn b common_pp.n Scalar.(negate one))) - batched_polys - - (* compute the batched polynomials A, B, C for the shared-permutation - argument; polynomial A (analogously B and C) can be computed by - batching polynomials a_i with powers of delta; or alternatively, by - applying an IFFT interpolation on the batched witness; we expect - the latter to be more efficient if the number of batched proofs - is over the threshold of [log2(n)] proofs, where [n] is the domain - size: this is because polynomial batching would require about - [n * nb_proofs] scalar operations (per polynomial) whereas the IFFT - would need [n * log2(n)]; such theoretical threshold has also been - empirically sustained with benchmarks *) - let build_batched_witness_polys pp {delta; _} f_blinds batched_wires f_wires - = - let logn = Z.log2 @@ Z.of_int pp.common_pp.n in - let batched_witness_polys = - SMap.mapi - (fun name wires_list -> - let batched_wires = SMap.find name batched_wires in - let f_blinds = SMap.find name f_blinds in - if List.compare_length_with wires_list logn > 0 then - (* we apply an IFFT on the batched witness *) - batched_wires_poly_of_batched_wires - pp - batched_wires - (delta, f_blinds) - else - (* Use capital for the batched wires *) - let wires_list = - List.map (SMap.update_keys String.capitalize_ascii) wires_list - in - (* we batched the a_i polynomials (analogously for b_i and c_i) *) - SMap.map (fun p -> Poly.linear_with_powers p delta) - @@ SMap.map_list_to_list_map wires_list) - f_wires - in - batched_witness_polys |> SMap.Aggregation.smap_of_smap_smap - (* For each circuits, compute the shared Z polynomial *) let build_f_map_perm pp {beta_perm = beta; gamma_perm = gamma; _} batched_wires = @@ -473,6 +383,7 @@ module Make_impl (PP : Polynomial_protocol.S) = struct ~beta ~gamma ~domain:pp.common_pp.domain + () in if pp.common_pp.zk then SMap.map @@ -501,7 +412,6 @@ module Make_impl (PP : Polynomial_protocol.S) = struct ~beta ~gamma ~domain:pp.common_pp.domain - ~circuit_size:circuit_pp.circuit_size in if pp.common_pp.zk then SMap.map @@ -512,32 +422,75 @@ module Make_impl (PP : Polynomial_protocol.S) = struct wires_list_map |> SMap.Aggregation.gather_maps ?shifts_map - let build_f_map_range_checks ?shifts_map pp - {beta_rc = beta; gamma_rc = gamma; _} wires_list_map = + let build_f_map_rc_1 ?shifts_map pp {delta; _} wires_list_map batched_wires + = + let rc_map, rc_z_evals = + SMap.mapi + (fun name w_list -> + let circuit_pp = SMap.find name pp.circuits_map in + if fst circuit_pp.range_checks = [] then ([], []) + else + List.map + (fun values -> + let rc_z_eval, rc_map = + RangeCheck.f_map_contribution_1 + ~range_checks:circuit_pp.range_checks + ~domain:pp.common_pp.domain + ~values + in + let rc_map = + if pp.common_pp.zk then + SMap.map + (fun f -> + fst (Poly.blind ~nb_blinds:3 pp.common_pp.n f)) + rc_map + else rc_map + in + (rc_map, rc_z_eval)) + w_list + |> List.split) + wires_list_map + |> SMap.to_pair + in + let batched_z_evals = + SMap.mapi + (fun name z_evals -> + if fst (SMap.find name pp.circuits_map).range_checks = [] then + SMap.empty + else + SMap.singleton + RangeCheck.batched_z_name + (Evaluations.linear_with_powers z_evals delta)) + rc_z_evals + in + let batched_values = + Perm.Shared_argument.merge_batched_values batched_z_evals batched_wires + in + (SMap.Aggregation.gather_maps ?shifts_map rc_map, batched_values) + + let build_f_map_rc_2 pp {beta_rc = beta; gamma_rc = gamma; _} batched_values + = SMap.mapi - (fun name w_list -> + (fun name values -> let circuit_pp = SMap.find name pp.circuits_map in - if fst circuit_pp.range_checks = [] then [] + if fst circuit_pp.range_checks = [] then SMap.empty else - List.map - (fun wires -> - let rc_map = - RangeCheck.f_map_contribution - ~permutation:circuit_pp.rc_permutation - ~beta - ~gamma - ~domain:pp.common_pp.domain - ~range_checks:circuit_pp.range_checks - ~values:wires - in - if pp.common_pp.zk then - SMap.map - (fun f -> fst (Poly.blind ~nb_blinds:3 pp.common_pp.n f)) - rc_map - else rc_map) - w_list) - wires_list_map - |> SMap.Aggregation.gather_maps ?shifts_map + let zs = + RangeCheck.f_map_contribution_2 + ~permutation:circuit_pp.rc_permutation + ~beta + ~gamma + ~domain:pp.common_pp.domain + ~values + in + if pp.common_pp.zk then + SMap.map + (* 3 blinds because the polynomial is evaluated at x and gx *) + (fun f -> fst (Poly.blind ~nb_blinds:3 pp.common_pp.n f)) + zs + else zs) + batched_values + |> SMap.Aggregation.smap_of_smap_smap let format_input_com (inputs_map : circuit_prover_input list SMap.t) = SMap.mapi @@ -573,30 +526,42 @@ module Make_impl (PP : Polynomial_protocol.S) = struct in Evaluations.compute_evaluations_update_map ~evaluations f_map - let build_perm_identities pp rd = + let build_perm_rc2_identities pp rd = SMap.mapi (fun circuit_name circuit_pp -> - let perm_identities = - (* Using the batched wires *) - let wires_names = - List.map - String.capitalize_ascii - (wire_names @@ Array.length circuit_pp.wires) - in + (* Using the batched wires *) + let wires_names = + List.map + String.capitalize_ascii + (wire_names @@ Array.length circuit_pp.wires) + in + let circuit_prefix = SMap.Aggregation.add_prefix circuit_name in + let perm_id = Perm.prover_identities - ~circuit_name + ~circuit_prefix ~wires_names ~beta:rd.beta_perm ~gamma:rd.gamma_perm ~n:pp.common_pp.n () in - perm_identities) + if fst circuit_pp.range_checks = [] then perm_id + else + let rc2_ids = + RangeCheck.prover_identities_2 + ~circuit_prefix + ~beta:rd.beta_rc + ~gamma:rd.gamma_rc + ~domain_size:pp.common_pp.n + () + in + + merge_prover_identities [perm_id; rc2_ids]) pp.circuits_map |> SMap.values |> merge_prover_identities - let build_gates_plook_rc_identities ?shifts_map pp - {beta_plook; gamma_plook; beta_rc; gamma_rc; _} inputs_map = + let build_gates_plook_rc1_identities ?shifts_map pp + {beta_plook; gamma_plook; _} inputs_map = let identities_map = SMap.mapi (fun circuit_name inputs_list -> @@ -608,6 +573,13 @@ module Make_impl (PP : Polynomial_protocol.S) = struct | None -> (0, List.length inputs_list) | Some shifts_map -> SMap.find circuit_name shifts_map in + let circuit_prefix = SMap.Aggregation.add_prefix circuit_name in + let proof_prefix i = + SMap.Aggregation.add_prefix + ~n:nb_proofs + ~i:(i + shift) + circuit_name + in let gates_identities = List.mapi (fun i inputs -> @@ -621,10 +593,9 @@ module Make_impl (PP : Polynomial_protocol.S) = struct circuit_pp.public_input_size in Gates.aggregate_prover_identities - ~circuit_name - ~nb_proofs + ~circuit_prefix ~input_coms_size - ~proof_idx:(i + shift) + ~proof_prefix:(proof_prefix i) ~gates:circuit_pp.gates ~public_inputs ~domain:pp.common_pp.domain @@ -634,11 +605,10 @@ module Make_impl (PP : Polynomial_protocol.S) = struct let plookup_identities = if not circuit_pp.ultra then [] else - List.init nb_proofs (fun proof_idx -> + List.init nb_proofs (fun i -> Plook.prover_identities - ~circuit_name - ~nb_proofs - ~proof_idx + ~circuit_prefix + ~proof_prefix:(proof_prefix i) ~wires_names ~alpha:circuit_pp.alpha ~beta:beta_plook @@ -646,21 +616,18 @@ module Make_impl (PP : Polynomial_protocol.S) = struct ~n:pp.common_pp.n ()) in - let rc_identities = + let rc1_identities = if fst circuit_pp.range_checks = [] then [] else - List.init nb_proofs (fun proof_idx -> - RangeCheck.prover_identities - ~circuit_name - ~nb_proofs - ~proof_idx - ~beta:beta_rc - ~gamma:gamma_rc + List.init nb_proofs (fun i -> + RangeCheck.prover_identities_1 + ~circuit_prefix + ~proof_prefix:(proof_prefix i) ~domain_size:pp.common_pp.n ()) in merge_prover_identities - (plookup_identities @ gates_identities @ rc_identities)) + (rc1_identities @ plookup_identities @ gates_identities)) inputs_map in merge_prover_identities (SMap.values identities_map) @@ -674,31 +641,50 @@ module Make_impl (PP : Polynomial_protocol.S) = struct let transcript = Transcript.expand Commitment.t cm_wires pp.transcript in let rd, transcript = build_gates_randomness transcript in - let batched_wires = build_batched_wires_values rd wires_list_map in + let batched_wires = + Perm.Shared_argument.build_batched_wires_values + ~delta:rd.delta + ~wires:wires_list_map + in - let f_map_contributions = + (* The new batched_wires is used for the RC shared perm argument *) + let f_map_contributions, batched_wires = let f_map_perm = build_f_map_perm pp rd batched_wires in let f_map_plook = build_f_map_plook pp rd wires_list_map in - let f_map_rc = build_f_map_range_checks pp rd wires_list_map in - SMap.union_disjoint_list [f_map_perm; f_map_plook; f_map_rc] + let f_map_rc1, batched_values = + build_f_map_rc_1 pp rd wires_list_map batched_wires + in + let f_map_rc2 = build_f_map_rc_2 pp rd batched_values in + ( SMap.union_disjoint_list + [f_map_perm; f_map_plook; f_map_rc1; f_map_rc2], + batched_values ) in let input_com_secrets = format_input_com inputs_map in let identities = - let perm_ids = build_perm_identities pp rd in - let gates_plook_rc_ids = - build_gates_plook_rc_identities pp rd inputs_map + let gates_plook_rc1_ids = + build_gates_plook_rc1_identities pp rd inputs_map in - merge_prover_identities [perm_ids; gates_plook_rc_ids] + let perm_rc2_ids = build_perm_rc2_identities pp rd in + merge_prover_identities [perm_rc2_ids; gates_plook_rc1_ids] in let eval_points = pp.common_pp.eval_points @ List.map (Fun.const [X]) input_com_secrets in + (* Here we introduced the use_batched_wires because f_wires does not contain rc stuff, which will be missing if batched wires polys are deduced from f_wires *) let batched_wires_polys = - build_batched_witness_polys pp rd f_blinds batched_wires f_wires + Perm.Shared_argument.build_batched_witness_polys + ~use_batched_wires: + (SMap.exists (fun _ c -> fst c.range_checks <> []) pp.circuits_map) + ~zero_knowledge:pp.common_pp.zk + ~domain:pp.common_pp.domain + ~delta:rd.delta + ~batched_wires + ~f:(f_wires, f_blinds) + () in let evaluations = @@ -791,10 +777,14 @@ module Make_impl (PP : Polynomial_protocol.S) = struct (fun circuit_name pi_list -> let circuit_pp = SMap.find circuit_name circuits_map in let nb_proofs = List.length pi_list in + let circuit_prefix = SMap.Aggregation.add_prefix circuit_name in + let proof_prefix i = + SMap.Aggregation.add_prefix ~n:nb_proofs ~i circuit_name + in let wires_names = wire_names Plompiler.Csir.nb_wires_arch in let perm_identities = Perm.verifier_identities - ~circuit_name + ~circuit_prefix ~wires_names ~nb_proofs ~generator @@ -806,52 +796,58 @@ module Make_impl (PP : Polynomial_protocol.S) = struct in let gates_identities = List.mapi - (fun proof_idx public_inputs -> + (fun i public_inputs -> Gates.aggregate_verifier_identities - ~circuit_name + ~circuit_prefix ~input_com_sizes:circuit_pp.input_com_sizes - ~nb_proofs - ~proof_idx ~gates:circuit_pp.gates ~public_inputs ~generator ~size_domain:n - ()) + () + ~proof_prefix:(proof_prefix i)) pi_list in let plookup_identities = if not circuit_pp.ultra then [] else - List.init nb_proofs (fun proof_idx -> + List.init nb_proofs (fun i -> Plook.verifier_identities - ~circuit_name - ~nb_proofs - ~proof_idx + ~circuit_prefix ~wires_names ~generator ~n ~alpha:circuit_pp.alpha ~beta:rd.beta_plook ~gamma:rd.gamma_plook + ~proof_prefix:(proof_prefix i) ()) in - let rc_identities = - if not circuit_pp.range_checks then [] - else - List.init nb_proofs (fun proof_idx -> - RangeCheck.verifier_identities - ~circuit_name - ~proof_idx - ~nb_proofs - ~beta:rd.beta_rc - ~gamma:rd.gamma_rc - ~domain_size:n - ~generator + if not circuit_pp.range_checks then + merge_verifier_identities + (perm_identities :: (plookup_identities @ gates_identities)) + else + let rc1_identities = + List.init nb_proofs (fun i -> + RangeCheck.verifier_identities_1 + ~circuit_prefix + ~proof_prefix:(proof_prefix i) ()) - in - merge_verifier_identities - (perm_identities - :: (plookup_identities @ gates_identities @ rc_identities))) + in + let rc2_identities = + RangeCheck.verifier_identities_2 + ~circuit_prefix + ~nb_proofs + ~beta:rd.beta_rc + ~gamma:rd.gamma_rc + ~delta:rd.delta + ~domain_size:n + ~generator + () + in + merge_verifier_identities + (perm_identities :: rc2_identities + :: (rc1_identities @ plookup_identities @ gates_identities))) public_inputs_map in merge_verifier_identities (SMap.values identities_map) diff --git a/src/lib_plonk/permutation_gate.ml b/src/lib_plonk/permutation_gate.ml index 00ae898c7c7699317de0a29762d57aa4f2626700..8d1de034c6ca5987ff572a10345f25089ee84715 100644 --- a/src/lib_plonk/permutation_gate.ml +++ b/src/lib_plonk/permutation_gate.ml @@ -181,7 +181,8 @@ module Permutation_gate_impl (PP : Polynomial_protocol.S) = struct let k = get_k i in (si_name i, Evaluations.mul_by_scalar k domain_evals))) - let ssigma_map_non_quadratic_residues permutation domain size = + let ssigma_map_non_quadratic_residues external_prefix permutation domain + size = let n = Domain.length domain in let ssigma_map = SMap.of_list @@ -194,7 +195,8 @@ module Permutation_gate_impl (PP : Polynomial_protocol.S) = struct let index = s_ij mod n in Scalar.mul coeff (Domain.get domain index)) in - (ss_name i, Evaluations.interpolation_fft2 domain coeff_list))) + ( external_prefix ^ ss_name i, + Evaluations.interpolation_fft2 domain coeff_list ))) in ssigma_map end @@ -244,9 +246,9 @@ module Permutation_gate_impl (PP : Polynomial_protocol.S) = struct res_evaluation (* evaluations must contain z’s evaluation *) - let prover_identities ~additionnal_prefix:a_pref ~prefix wires_names beta - gamma n evaluations = - let z_name = a_pref z_name in + let prover_identities ~external_prefix:e_pref ~prefix wires_names beta gamma + n evaluations = + let z_name = e_pref z_name in let raw_z_name = z_name in let zg_name = zg_name z_name in let z_evaluation = @@ -282,7 +284,7 @@ module Permutation_gate_impl (PP : Polynomial_protocol.S) = struct in let g_evaluation = let ss_names = - List.init nb_wires (fun i -> prefix @@ a_pref (ss_name i)) + List.init nb_wires (fun i -> prefix @@ e_pref (ss_name i)) in compute_prime ~prefix @@ -320,8 +322,8 @@ module Permutation_gate_impl (PP : Polynomial_protocol.S) = struct in SMap.of_list [ - (prefix (a_pref "Perm.a"), identity_l1_z); - (prefix (a_pref "Perm.b"), identity_zfg); + (prefix (e_pref "Perm.a"), identity_l1_z); + (prefix (e_pref "Perm.b"), identity_zfg); ] (* compute_Z performs the following steps in the two loops. @@ -391,6 +393,100 @@ module Permutation_gate_impl (PP : Polynomial_protocol.S) = struct Evaluations.interpolation_fft2 domain scalar_array_Z end + (* The shared permutation argument consists of leveraging the fact that + all proofs of the same circuit type share the same permutation + for ensuring the copy-satisfiability. + This allows us to run a single permutation argument on a linear + combination of the wire polynomials of all same-circuit proofs. + Namely, let a_i(X), b_i(X), c_i(X) be the wire polynomials of the + i-th proof. Let delta be some scalar sampled after (and based on) + a commitment to all a_i, b_i, c_i and consider batched polynomials: + A(X) := \sum_i delta^{i-1} a_i(X) + B(X) := \sum_i delta^{i-1} b_i(X) + C(X) := \sum_i delta^{i-1} c_i(X) + We will perform a single permutation argument for A, B and C. *) + module Shared_argument = struct + let build_batched_wires_values ~delta ~wires:wires_list_map = + (* agg_map = {a -> [] ; b -> [] ; …} *) + let agg_map = + SMap.(map (Fun.const []) (List.hd (choose wires_list_map |> snd))) + in + (* builds {a -> linear(a in l) ; b -> linear(b in l) ; …} *) + let aggreg_wires_list l = + List.fold_left + (fun acc wires -> (SMap.mapi (fun k v -> SMap.find k wires :: v)) acc) + agg_map + (List.rev l) + |> SMap.map (fun ws_list -> + Evaluations.linear_with_powers ws_list delta) + in + SMap.map aggreg_wires_list wires_list_map + |> SMap.(map (update_keys String.capitalize_ascii)) + + (* For each circuit, interpolates the batched wires A, B, C from the + batched witness *) + let batched_wires_poly_of_batched_wires (zk, n, domain) batched_wires + (delta, f_blinds) = + let batched_polys = + SMap.map (fun w -> Evaluations.interpolation_fft domain w) batched_wires + in + if not zk then batched_polys + else + (* delta is only used to batched the blinds, the polys are computed + from a witness batched with delta already *) + let batched_blinds = + let f_blinds = List.map (fun b -> Option.get b) f_blinds in + SMap.map_list_to_list_map f_blinds + |> SMap.map (fun p -> Poly.linear_with_powers p delta) + in + SMap.mapi + (fun name f -> + let b = SMap.find name batched_blinds in + Poly.(f + mul_xn b n Scalar.(negate one))) + batched_polys + + (* compute the batched polynomials A, B, C for the shared-permutation + argument; polynomial A (analogously B and C) can be computed by + batching polynomials a_i with powers of delta; or alternatively, by + applying an IFFT interpolation on the batched witness; we expect + the latter to be more efficient if the number of batched proofs + is over the threshold of [log2(n)] proofs, where [n] is the domain + size: this is because polynomial batching would require about + [n * nb_proofs] scalar operations (per polynomial) whereas the IFFT + would need [n * log2(n)]; such theoretical threshold has also been + empirically sustained with benchmarks *) + let build_batched_witness_polys ?(use_batched_wires = false) ~zero_knowledge + ~domain ~delta ~batched_wires ~f:(f_wires, f_blinds) () = + let n = Domain.length domain in + let logn = Z.log2 @@ Z.of_int n in + let batched_witness_polys = + SMap.mapi + (fun name wires_list -> + let batched_wires = SMap.find name batched_wires in + let f_blinds = SMap.find name f_blinds in + if List.compare_length_with wires_list logn > 0 || use_batched_wires + then + (* we apply an IFFT on the batched witness *) + batched_wires_poly_of_batched_wires + (zero_knowledge, n, domain) + batched_wires + (delta, f_blinds) + else + (* Use capital for the batched wires *) + let wires_list = + List.map (SMap.update_keys String.capitalize_ascii) wires_list + in + (* we batched the a_i polynomials (analogously for b_i and c_i) *) + SMap.map (fun p -> Poly.linear_with_powers p delta) + @@ SMap.map_list_to_list_map wires_list) + f_wires + in + batched_witness_polys |> SMap.Aggregation.smap_of_smap_smap + + let merge_batched_values m1 m2 = + SMap.mapi (fun k v -> SMap.union_disjoint v (SMap.find k m1)) m2 + end + (* max degree needed is the degree of Perm.b, which is sum of wire’s degree plus z degree *) let polynomials_degree ~nb_wires = nb_wires + 1 @@ -414,8 +510,12 @@ module Permutation_gate_impl (PP : Polynomial_protocol.S) = struct As a consequence, deg(T)-deg(Zs) = (n+2)+3(n+1) - n = 3n+5 (for gates’ identity verification, max degree is degree of qM×fL×fR which is (n-1)+(n+1)+(n+1) < 3n+5) *) - let preprocessing ~domain ~permutation ~nb_wires () = - Preprocessing.ssigma_map_non_quadratic_residues permutation domain nb_wires + let preprocessing ?(external_prefix = "") ~domain ~permutation ~nb_wires () = + Preprocessing.ssigma_map_non_quadratic_residues + external_prefix + permutation + domain + nb_wires let common_preprocessing ~nb_wires ~domain ~evaluations = let sid_evals = Preprocessing.evaluations_sid nb_wires evaluations in @@ -423,37 +523,43 @@ module Permutation_gate_impl (PP : Polynomial_protocol.S) = struct let l1_map = SMap.singleton l1 @@ Preprocessing.compute_l1 domain in Evaluations.compute_evaluations_update_map ~evaluations l1_map - let prover_identities ?(prefix = "") ?(circuit_name = "") ~wires_names ~beta - ~gamma ~n () = - let additionnal_prefix s = - if s = z_name && prefix <> "" then prefix ^ "Perm_" ^ s else prefix ^ s - in - let prefix = SMap.Aggregation.add_prefix circuit_name in + let external_prefix_fun ext s = + (* This is used to differenciate the case where the permutation gate is + called by PlonK & the case where it’s used by an other gate (ie RC) + Depending on that, we want to change Z, Ss & identities names *) + if s = z_name && ext <> "" then ext ^ "Perm_" ^ s else ext ^ s + + let prover_identities ?(external_prefix = "") ?(circuit_prefix = Fun.id) + ~wires_names ~beta ~gamma ~n () = + let external_prefix = external_prefix_fun external_prefix in fun evaluations -> Permutation_poly.prover_identities - ~additionnal_prefix - ~prefix + ~external_prefix + ~prefix:circuit_prefix wires_names beta gamma n evaluations - let verifier_identities ?(prefix = "") ?(circuit_name = "") ~nb_proofs - ~generator ~n ~wires_names ~beta ~gamma ~delta () = - let a_pref s = - if s = z_name && prefix <> "" then prefix ^ "Perm_" ^ s else prefix ^ s - in - let prefix = SMap.Aggregation.add_prefix circuit_name in - let prefix_j j = - SMap.Aggregation.add_prefix ~n:nb_proofs ~i:j circuit_name + let verifier_identities ?(external_prefix = "") ?(circuit_prefix = Fun.id) + ~nb_proofs ~generator ~n ~wires_names ~beta ~gamma ~delta () = + let e_pref = external_prefix_fun external_prefix in + let prefix_j i = + SMap.Aggregation.add_prefix + ~no_sep:true + ~n:nb_proofs + ~i + (circuit_prefix "") in - let z_name = a_pref z_name in + let z_name = e_pref z_name in let ss_names = - List.init (List.length wires_names) (fun i -> a_pref (ss_name i)) + List.init (List.length wires_names) (fun i -> e_pref (ss_name i)) in fun x answers -> - let get_ss i = get_answer answers X (prefix @@ List.nth ss_names i) in + let get_ss i = + get_answer answers X (circuit_prefix @@ List.nth ss_names i) + in (* compute the delta-aggregated wire evaluations at x for each wire name *) let batched = let wire_j w j = get_answer answers X @@ prefix_j j w in @@ -461,8 +567,8 @@ module Permutation_gate_impl (PP : Polynomial_protocol.S) = struct (fun w -> Fr_generation.batch delta (List.init nb_proofs (wire_j w))) wires_names in - let z = get_answer answers X (prefix z_name) in - let zg = get_answer answers GX (prefix z_name) in + let z = get_answer answers X (circuit_prefix z_name) in + let zg = get_answer answers GX (circuit_prefix z_name) in (* compute the first identity: (Z(x) - 1) * L1(x) *) let res1 = Scalar.( @@ -482,11 +588,15 @@ module Permutation_gate_impl (PP : Polynomial_protocol.S) = struct (multiply @@ (zg :: zg_factors)) in SMap.of_list - [(prefix (a_pref "Perm.a"), res1); (prefix (a_pref "Perm.b"), res2)] + [ + (circuit_prefix (e_pref "Perm.a"), res1); + (circuit_prefix (e_pref "Perm.b"), res2); + ] - let f_map_contribution ~permutation ~values ~beta ~gamma ~domain = + let f_map_contribution ?(external_prefix = "") ~permutation ~values ~beta + ~gamma ~domain () = SMap.singleton - z_name + (external_prefix_fun external_prefix z_name) (Permutation_poly.compute_Z permutation domain beta gamma values) let cs ~sum_alpha_i ~l1 ~ss_list ~beta ~gamma ~delta ~x ~z ~zg ~wires = @@ -527,7 +637,9 @@ module type S = sig val build_permutation : int array array -> int array + (* external_prefix is an additionnal prefix for Ss, Z and identities names ; it is used by Range check gate *) val preprocessing : + ?external_prefix:string -> domain:Domain.t -> permutation:int array -> nb_wires:int -> @@ -540,11 +652,9 @@ module type S = sig evaluations:Evaluations.t SMap.t -> Evaluations.t SMap.t - (* prefix is an additionnal prefix for Ss, Z and identities names ; it is - used by Range check gate *) val prover_identities : - ?prefix:string -> - ?circuit_name:string -> + ?external_prefix:string -> + ?circuit_prefix:(string -> string) -> wires_names:string list -> beta:Scalar.t -> gamma:Scalar.t -> @@ -552,11 +662,9 @@ module type S = sig unit -> prover_identities - (* prefix is an additionnal prefix for Ss, Z and identities names ; it is - used by Range check gate *) val verifier_identities : - ?prefix:string -> - ?circuit_name:string -> + ?external_prefix:string -> + ?circuit_prefix:(string -> string) -> nb_proofs:int -> generator:Scalar.t -> n:int -> @@ -568,11 +676,13 @@ module type S = sig verifier_identities val f_map_contribution : + ?external_prefix:string -> permutation:int array -> values:Evaluations.t SMap.t -> - beta:Poly.scalar -> - gamma:Poly.scalar -> + beta:Scalar.t -> + gamma:Scalar.t -> domain:Domain.t -> + unit -> Poly.t SMap.t val cs : @@ -587,6 +697,32 @@ module type S = sig zg:L.scalar L.repr -> wires:L.scalar L.repr list list -> (L.scalar L.repr * L.scalar L.repr) L.t + + module Shared_argument : sig + val build_batched_wires_values : + delta:Scalar.t -> + wires:Evaluations.t SMap.t list SMap.t -> + Evaluations.t SMap.t SMap.t + + val batched_wires_poly_of_batched_wires : + bool * int * Domain.t -> + Evaluations.t SMap.t -> + Scalar.t * Poly.t SMap.t option list -> + Poly.t SMap.t + + val build_batched_witness_polys : + ?use_batched_wires:bool -> + zero_knowledge:bool -> + domain:Domain.t -> + delta:Scalar.t -> + batched_wires:Evaluations.t SMap.t SMap.t -> + f:Poly.t SMap.t list SMap.t * Poly.t SMap.t option list SMap.t -> + unit -> + Poly.t SMap.t + + val merge_batched_values : + 'a SMap.t SMap.t -> 'a SMap.t SMap.t -> 'a SMap.t SMap.t + end end module Permutation_gate (PP : Polynomial_protocol.S) : S with module PP = PP = diff --git a/src/lib_plonk/plookup_gate.ml b/src/lib_plonk/plookup_gate.ml index 50c148e716ab957e088f5d5f9e49e8f595b81292..4189694c2679402f96d4f456c2dc2cafc05f371d 100644 --- a/src/lib_plonk/plookup_gate.ml +++ b/src/lib_plonk/plookup_gate.ml @@ -80,12 +80,12 @@ module Plookup_gate_impl (PP : Polynomial_protocol.S) = struct | Some alpha -> alpha | None -> failwith "Plookup alpha is undefined" - let gate_identity ~prefix_common ~prefix ~n ~generator ~wires_names ~alpha + let gate_identity ~circuit_prefix ~prefix ~n ~generator ~wires_names ~alpha ~beta ~gamma : verifier_identities = fun x answers -> - let q_label_name = prefix_common q_label in - let q_table_name = prefix_common q_table in - let t_name = prefix_common t in + let q_label_name = circuit_prefix q_label in + let q_table_name = circuit_prefix q_table in + let t_name = circuit_prefix t in let z_name = prefix z in let f_name = prefix f in let h1_name = prefix h1 in @@ -168,12 +168,12 @@ module Plookup_gate_impl (PP : Polynomial_protocol.S) = struct in SMap.add (prefix "Plookup.ultra") id_ultra identities - let prover_identities ~prefix_common ~prefix ~wires_names ~alpha ~beta ~gamma - n : prover_identities = + let prover_identities_aux ~circuit_prefix ~prefix ~wires_names ~alpha ~beta + ~gamma n : prover_identities = fun evaluations -> - let q = prefix_common q_label in - let q_table = prefix_common q_table in - let t = prefix_common t in + let q = circuit_prefix q_label in + let q_table = circuit_prefix q_table in + let t = circuit_prefix t in let z = prefix z in let h1 = prefix h1 in let h2 = prefix h2 in @@ -505,25 +505,24 @@ module Plookup_gate_impl (PP : Polynomial_protocol.S) = struct Array.append t padding) concatenated_table - let prover_identities ?(circuit_name = "") ~proof_idx ~nb_proofs ~wires_names + let prover_identities ?(circuit_prefix = Fun.id) ~proof_prefix ~wires_names ~alpha ~beta ~gamma ~n () : prover_identities = let alpha = get_alpha alpha in - let prefix_common = SMap.Aggregation.add_prefix circuit_name in - let prefix = - SMap.Aggregation.add_prefix ~n:nb_proofs ~i:proof_idx circuit_name - in - prover_identities ~prefix_common ~prefix ~wires_names ~alpha ~beta ~gamma n + prover_identities_aux + ~circuit_prefix + ~prefix:proof_prefix + ~wires_names + ~alpha + ~beta + ~gamma + n - let verifier_identities ?(circuit_name = "") ~proof_idx ~nb_proofs ~n - ~generator ~wires_names ~alpha ~beta ~gamma () : verifier_identities = + let verifier_identities ?(circuit_prefix = Fun.id) ~proof_prefix ~n ~generator + ~wires_names ~alpha ~beta ~gamma () : verifier_identities = let alpha = get_alpha alpha in - let prefix_common = SMap.Aggregation.add_prefix circuit_name in - let prefix = - SMap.Aggregation.add_prefix ~n:nb_proofs ~i:proof_idx circuit_name - in gate_identity - ~prefix_common - ~prefix + ~circuit_prefix + ~prefix:proof_prefix ~n ~generator ~wires_names @@ -534,8 +533,7 @@ module Plookup_gate_impl (PP : Polynomial_protocol.S) = struct (* wires must be correctly padded *) (*TODO : do this in evaluation*) (*TODO : use mul z_s*) - let f_map_contribution ~wires ~gates ~tables ~alpha ~beta ~gamma ~domain - ~circuit_size:_ = + let f_map_contribution ~wires ~gates ~tables ~alpha ~beta ~gamma ~domain = (* TODO : remove this conversion *) let wires = SMap.map Evaluations.to_array wires in let size_domain = Domain.length domain in @@ -601,9 +599,8 @@ module type S = sig Poly.t SMap.t val prover_identities : - ?circuit_name:string -> - proof_idx:int -> - nb_proofs:int -> + ?circuit_prefix:(string -> string) -> + proof_prefix:(string -> string) -> wires_names:string list -> alpha:Scalar.t option -> beta:Scalar.t -> @@ -613,9 +610,8 @@ module type S = sig prover_identities val verifier_identities : - ?circuit_name:string -> - proof_idx:int -> - nb_proofs:int -> + ?circuit_prefix:(string -> string) -> + proof_prefix:(string -> string) -> n:int -> generator:Scalar.t -> wires_names:string list -> @@ -633,7 +629,6 @@ module type S = sig beta:Scalar.t -> gamma:Scalar.t -> domain:Domain.t -> - circuit_size:int -> PP.PC.secret end diff --git a/src/lib_plonk/range_check_gate.ml b/src/lib_plonk/range_check_gate.ml index 33b5f30e561b5eadd57b6b64d8fafaf65bdd094b..25356969f050d0747d558651e66f0d44b84c7a98 100644 --- a/src/lib_plonk/range_check_gate.ml +++ b/src/lib_plonk/range_check_gate.ml @@ -46,42 +46,68 @@ open Identities module type S = sig module PP : Polynomial_protocol.S + val batched_z_name : string + val build_permutation : range_checks:int list * int -> size_domain:int -> int array - val common_preprocessing : unit -> 'a SMap.t - val preprocessing : permutation:int array -> range_checks:'a list * int -> domain:Domain.t -> Poly.t SMap.t - val f_map_contribution : + (* Builds the pure range check proof polynomials *) + val f_map_contribution_1 : + range_checks:int list * int -> + domain:Domain.t -> + values:Evaluations.t SMap.t -> + Evaluations.t * Poly.t SMap.t + + (* Builds the shared permutation proof polynomials for the range check proof polynomials built with f_map_contribution_1 + [values] must contain the wire polynomial that is being range checked and its range check proof polynomial, each in aggregated version + *) + val f_map_contribution_2 : permutation:int array -> - beta:Scalar.t -> - gamma:Scalar.t -> + beta:Poly.scalar -> + gamma:Poly.scalar -> domain:Domain.t -> - range_checks:int list * int -> values:Evaluations.t SMap.t -> Poly.t SMap.t - val prover_identities : - ?circuit_name:string -> - nb_proofs:int -> - proof_idx:int -> + (* Builds the pure range check identities *) + val prover_identities_1 : + ?circuit_prefix:(string -> string) -> + proof_prefix:(string -> string) -> + domain_size:int -> + unit -> + prover_identities + + (* Builds the permutation identities for the range check polynomials *) + val prover_identities_2 : + ?circuit_prefix:(string -> string) -> beta:Scalar.t -> gamma:Scalar.t -> domain_size:int -> unit -> prover_identities - val verifier_identities : - ?circuit_name:string -> + (* Builds the pure range check identities *) + val verifier_identities_1 : + ?circuit_prefix:(string -> string) -> + proof_prefix:(string -> string) -> + unit -> + Scalar.t -> + Scalar.t SMap.t SMap.t -> + Scalar.t SMap.t + + (* Builds the permutation identities for the range check polynomials *) + val verifier_identities_2 : + ?circuit_prefix:(string -> string) -> nb_proofs:int -> - proof_idx:int -> beta:Scalar.t -> gamma:Scalar.t -> + delta:Scalar.t -> domain_size:int -> generator:Scalar.t -> unit -> @@ -99,12 +125,14 @@ module Range_check_gate_impl (PP : Polynomial_protocol.S) = struct let z_name = "RC_Z" - let z_perm_name = "RC_Perm_Z" - - let ids_label = "RC_Perm" + let rc_prefix = "RC_" let wire = Plompiler.Csir.wire_name 0 + let batched_wire = String.capitalize_ascii wire + + let batched_z_name = "RC_Z_BATCHED" + type public_parameters = Poly.t SMap.t let zero, one, two = Scalar.(zero, one, one + one) @@ -151,44 +179,54 @@ module Range_check_gate_impl (PP : Polynomial_protocol.S) = struct proofs as we do for wires ; for now & simplicity, we don’t handle several proofs in one circuit *) module Permutation = struct - module Perm = Permutation_gate.Permutation_gate_impl (PP) + module Perm = Permutation_gate.Permutation_gate (PP) + + let external_prefix = rc_prefix let preprocessing ~permutation ~domain = - let ss_map = - Perm.Preprocessing.ssigma_map_non_quadratic_residues - permutation - domain - 2 - in - SMap.update_keys (String.cat "RC_") ss_map + Perm.preprocessing ~external_prefix ~domain ~permutation ~nb_wires:2 () - let f_map_contribution ~permutation ~beta ~gamma ~domain ~values = - SMap.singleton - z_perm_name - (Perm.Permutation_poly.compute_Z permutation domain beta gamma values) + let f_map_contribution ~permutation ~beta ~gamma ~domain + ~values:batched_values = + let values = + SMap.of_list + [ + (batched_wire, SMap.find batched_wire batched_values); + (batched_z_name, SMap.find batched_z_name batched_values); + ] + in + Perm.f_map_contribution + ~external_prefix + ~permutation + ~values + ~beta + ~gamma + ~domain + () - let prover_identities ~prefix_common ~prefix ~beta ~gamma domain_size = + let prover_identities ?(circuit_prefix = Fun.id) ~beta ~gamma ~domain_size + () = Perm.prover_identities - ~prefix:"RC_" - ~circuit_name:prefix_common - ~wires_names:[prefix z_name; prefix wire] + ~external_prefix + ~circuit_prefix + ~wires_names:[batched_z_name; batched_wire] ~beta ~gamma ~n:domain_size () - let verifier_identities ~prefix_common ~prefix ~beta ~gamma domain_size - generator = + let verifier_identities ?(circuit_prefix = Fun.id) ~nb_proofs ~beta ~gamma + ~delta ~domain_size ~generator () = Perm.verifier_identities - ~prefix:"RC_" - ~circuit_name:prefix_common - ~nb_proofs:1 + ~external_prefix + ~circuit_prefix + ~nb_proofs ~generator ~n:domain_size - ~wires_names:[prefix z_name; prefix wire] + ~wires_names:[z_name; wire] ~beta ~gamma - ~delta:one + ~delta () end @@ -268,79 +306,77 @@ module Range_check_gate_impl (PP : Polynomial_protocol.S) = struct let evals, z = compute_Z domain upper_bound k check_indices wire in (evals, SMap.of_list [(z_name, z)]) - let prover_identities ~prefix_common ~prefix n = - let prefix_common = SMap.Aggregation.add_prefix prefix_common in - fun evaluations -> - let z_evaluation = - Evaluations.find_evaluation evaluations (prefix z_name) + let prover_identities ?(circuit_prefix = Fun.id) ~proof_prefix:prefix + ~domain_size:n () evaluations = + let z_evaluation = + Evaluations.find_evaluation evaluations (prefix z_name) + in + let z_evaluation_len = Evaluations.length z_evaluation in + let tmp_evaluation = Evaluations.create z_evaluation_len in + let tmp2_evaluation = Evaluations.create z_evaluation_len in + let idrca_evaluation = Evaluations.create z_evaluation_len in + let idrcb_evaluation = Evaluations.create z_evaluation_len in + + (* Z × (1-Z) × Lnin1 *) + let identity_rca = + let lnin1_evaluation = + Evaluations.find_evaluation evaluations (circuit_prefix lnin1) in - let z_evaluation_len = Evaluations.length z_evaluation in - let tmp_evaluation = Evaluations.create z_evaluation_len in - let tmp2_evaluation = Evaluations.create z_evaluation_len in - let idrca_evaluation = Evaluations.create z_evaluation_len in - let idrcb_evaluation = Evaluations.create z_evaluation_len in - - (* Z × (1-Z) × Lnin1 *) - let identity_rca = - let lnin1_evaluation = - Evaluations.find_evaluation evaluations (prefix_common lnin1) - in - let one_m_z_evaluation = - Evaluations.linear_c - ~res:tmp_evaluation - ~linear_coeffs:[mone] - ~evaluations:[z_evaluation] - ~add_constant:one - () - in - Evaluations.mul_c - ~res:idrca_evaluation - ~evaluations:[z_evaluation; one_m_z_evaluation; lnin1_evaluation] + let one_m_z_evaluation = + Evaluations.linear_c + ~res:tmp_evaluation + ~linear_coeffs:[mone] + ~evaluations:[z_evaluation] + ~add_constant:one () in - (* (Z - 2Zg) × (1 - Z + 2Zg) × Pnin1 *) - let identity_rcb = - let pnin1_evaluation = - Evaluations.find_evaluation evaluations (prefix_common pnin1) - in - let z_min_2Zg_evaluation = - Evaluations.linear_c - ~res:tmp_evaluation - ~linear_coeffs:[one; mtwo] - ~composition_gx:([0; 1], n) - ~evaluations:[z_evaluation; z_evaluation] - () - in - let one_m_Z_p_2Zg_evaluation = - Evaluations.linear_c - ~res:tmp2_evaluation - ~linear_coeffs:[mone] - ~evaluations:[z_min_2Zg_evaluation] - ~add_constant:one - () - in - Evaluations.mul_c - ~res:idrcb_evaluation - ~evaluations: - [z_min_2Zg_evaluation; one_m_Z_p_2Zg_evaluation; pnin1_evaluation] + Evaluations.mul_c + ~res:idrca_evaluation + ~evaluations:[z_evaluation; one_m_z_evaluation; lnin1_evaluation] + () + in + (* (Z - 2Zg) × (1 - Z + 2Zg) × Pnin1 *) + let identity_rcb = + let pnin1_evaluation = + Evaluations.find_evaluation evaluations (circuit_prefix pnin1) + in + let z_min_2Zg_evaluation = + Evaluations.linear_c + ~res:tmp_evaluation + ~linear_coeffs:[one; mtwo] + ~composition_gx:([0; 1], n) + ~evaluations:[z_evaluation; z_evaluation] () in - SMap.of_list - [(prefix "RC.a", identity_rca); (prefix "RC.b", identity_rcb)] - - let verifier_identities ~prefix_common ~prefix = - let prefix_common = SMap.Aggregation.add_prefix prefix_common in - fun _x answers -> - let z = get_answer answers X (prefix z_name) in - let zg = get_answer answers GX (prefix z_name) in - let lnin1 = get_answer answers X (prefix_common lnin1) in - let pnin1 = get_answer answers X (prefix_common pnin1) in - let identity_rca = Scalar.(z * (one + negate z) * lnin1) in - let identity_rcb = - Scalar.((z + (mtwo * zg)) * (one + negate z + (two * zg)) * pnin1) + let one_m_Z_p_2Zg_evaluation = + Evaluations.linear_c + ~res:tmp2_evaluation + ~linear_coeffs:[mone] + ~evaluations:[z_min_2Zg_evaluation] + ~add_constant:one + () in - SMap.of_list - [(prefix "RC.a", identity_rca); (prefix "RC.b", identity_rcb)] + Evaluations.mul_c + ~res:idrcb_evaluation + ~evaluations: + [z_min_2Zg_evaluation; one_m_Z_p_2Zg_evaluation; pnin1_evaluation] + () + in + SMap.of_list + [(prefix "RC.a", identity_rca); (prefix "RC.b", identity_rcb)] + + let verifier_identities ?(circuit_prefix = Fun.id) ~proof_prefix:prefix () + _x answers = + let z = get_answer answers X (prefix z_name) in + let zg = get_answer answers GX (prefix z_name) in + let lnin1 = get_answer answers X (circuit_prefix lnin1) in + let pnin1 = get_answer answers X (circuit_prefix pnin1) in + let identity_rca = Scalar.(z * (one + negate z) * lnin1) in + let identity_rcb = + Scalar.((z + (mtwo * zg)) * (one + negate z + (two * zg)) * pnin1) + in + SMap.of_list + [(prefix "RC.a", identity_rca); (prefix "RC.b", identity_rcb)] end let preprocessing ~permutation ~range_checks ~domain = @@ -350,65 +386,17 @@ module Range_check_gate_impl (PP : Polynomial_protocol.S) = struct let perm = Permutation.preprocessing ~permutation ~domain in SMap.union_disjoint rc perm - let common_preprocessing () = SMap.empty + let f_map_contribution_1 = RangeChecks.f_map_contribution - let f_map_contribution ~permutation ~beta ~gamma ~domain ~range_checks - ~(values : Evaluations.t SMap.t) = - let values = SMap.singleton wire (SMap.find wire values) in - let z_evals, f_rc = - RangeChecks.f_map_contribution ~range_checks ~domain ~values - in - let f_perm = - Permutation.f_map_contribution - ~permutation - ~beta - ~gamma - ~domain - ~values:(SMap.add_unique z_name z_evals values) - in - SMap.union_disjoint f_rc f_perm + let f_map_contribution_2 = Permutation.f_map_contribution - let prover_identities ?(circuit_name = "") ~nb_proofs ~proof_idx ~beta ~gamma - ~domain_size () = - let proof_prefix = - SMap.Aggregation.add_prefix ~n:nb_proofs ~i:proof_idx "" - in - let prefix s = SMap.Aggregation.add_prefix circuit_name (proof_prefix s) in - let rc_ids = - RangeChecks.prover_identities - ~prefix_common:circuit_name - ~prefix - domain_size - in - let perm_ids = - Permutation.prover_identities - ~prefix_common:circuit_name - ~prefix:proof_prefix - ~beta - ~gamma - domain_size - in - Identities.merge_prover_identities [rc_ids; perm_ids] + let prover_identities_1 = RangeChecks.prover_identities - let verifier_identities ?(circuit_name = "") ~nb_proofs ~proof_idx ~beta - ~gamma ~domain_size ~generator () = - let proof_prefix = - SMap.Aggregation.add_prefix ~n:nb_proofs ~i:proof_idx "" - in - let prefix s = SMap.Aggregation.add_prefix circuit_name (proof_prefix s) in - let rc_ids = - RangeChecks.verifier_identities ~prefix_common:circuit_name ~prefix - in - let perm_ids = - Permutation.verifier_identities - ~prefix_common:circuit_name - ~prefix:proof_prefix - ~beta - ~gamma - domain_size - generator - in - Identities.merge_verifier_identities [rc_ids; perm_ids] + let prover_identities_2 = Permutation.prover_identities + + let verifier_identities_1 = RangeChecks.verifier_identities + + let verifier_identities_2 = Permutation.verifier_identities end module Range_check_gate (PP : Polynomial_protocol.S) : S with module PP = PP = diff --git a/src/lib_plonk/sMap.ml b/src/lib_plonk/sMap.ml index 439e41235be8dcc56638408a4eaae6e61d0b0307..b58659a49133d07a831c57f5295083777ae62eb0 100644 --- a/src/lib_plonk/sMap.ml +++ b/src/lib_plonk/sMap.ml @@ -56,6 +56,8 @@ module StringMap = struct (List.map (fun (k, v) -> k ^ ": " ^ show_inner v) (bindings m)) ^ "\n}" + let to_pair m = (map fst m, map snd m) + let add_unique k v m = if mem k m then raise @@ -126,8 +128,8 @@ module StringMap = struct let len = String.length (string_of_int (n - 1)) in String.(make (len - length str) '0') ^ str - let add_prefix ?(n = 1) ?(i = 0) ?(shift = 0) prefix str = - let prefix = if prefix = "" then "" else prefix ^ sep in + let add_prefix ?(no_sep = false) ?(n = 1) ?(i = 0) ?(shift = 0) prefix str = + let prefix = if prefix = "" || no_sep then prefix else prefix ^ sep in if n = 1 then prefix ^ str else prefix ^ padded ~n (i + shift) ^ sep ^ str let prefix_map ?n ?i ?shift prefix str_map = @@ -186,6 +188,8 @@ module type S = sig val values : 'a t -> 'a list + val to_pair : ('a * 'b) t -> 'a t * 'b t + (* [add_unique k v map] adds [k -> v] to [map] & throw an error if [k] is already in [map] *) @@ -222,9 +226,19 @@ module type S = sig allow a numbering until [n] with the same number of caracters for instance, [prefix ~n:11 ~i:5 ~shift:1 "hello" "world"] will return "06~hello~world" + [no_sep] is false by default ; if set to true, the separator before the + string to prefix will be ommitted : + [prefix ~no_sep:true ~n:11 ~i:5 ~shift:1 "hello" "world"] will return + "06~helloworld" *) val add_prefix : - ?n:int -> ?i:int -> ?shift:int -> string -> string -> string + ?no_sep:bool -> + ?n:int -> + ?i:int -> + ?shift:int -> + string -> + string -> + string (* adds prefix to each key of str_map ; [i] will be added as a string before the prefix diff --git a/src/lib_plonk/test/test-quick.expected b/src/lib_plonk/test/test-quick.expected index 51afda13c935874959a46be832f85a018d382941..8f2fd01a5570d2e23d4328ce2cb5312e191ce376 100644 --- a/src/lib_plonk/test/test-quick.expected +++ b/src/lib_plonk/test/test-quick.expected @@ -1,14 +1,26 @@ -Range_Checks_single: -Proof size: 2.83 KB -Proof hash: dedefb61d0f1d4c05dc7b2266dfa36d18c464bc41316c0d5f1a1e5ae202ac713 -Prover_pp hash: dab7b169be4d3b77665be6e6e5b4bdc1d0af528f767fa71ba1083f40d1456f52 -Verifier_pp hash: 3d0b01c7e68032c660edab4670ea900cccbed1c10c2729012051e09e585131c3 - -Range_Checks_single: -Proof size: 2.83 KB -Proof hash: dedefb61d0f1d4c05dc7b2266dfa36d18c464bc41316c0d5f1a1e5ae202ac713 -Prover_pp hash: dab7b169be4d3b77665be6e6e5b4bdc1d0af528f767fa71ba1083f40d1456f52 -Verifier_pp hash: 3d0b01c7e68032c660edab4670ea900cccbed1c10c2729012051e09e585131c3 +RC_single: +Proof size: 2.45 KB +Proof hash: f1166d7a1937b4a8b7979140420f3ad9026091337d97a601ec04bfa35c108cf3 +Prover_pp hash: e3d67d7e6f097e109a3fe69c078eab8f80635533894f4c47db0a28112d7cb95f +Verifier_pp hash: dec8841117c527f3328402be2b5e3e7119639ea0e497c6181621bfcad89a3493 + +RC_multi: +Proof size: 5.21 KB +Proof hash: c1b8b00e15eda5dc92b6161bc30a7290268d5694e6b274e79132c0246e693b98 +Prover_pp hash: 2c4d4cb9a62637a4247d4d4d0264c287e17173259f7d199880ebf18ae835b1e9 +Verifier_pp hash: c647c30e4a9584774a2020d9feafecdd70c0e74300cb93ef18383998711bd59e + +RC_single: +Proof size: 2.45 KB +Proof hash: f1166d7a1937b4a8b7979140420f3ad9026091337d97a601ec04bfa35c108cf3 +Prover_pp hash: e3d67d7e6f097e109a3fe69c078eab8f80635533894f4c47db0a28112d7cb95f +Verifier_pp hash: dec8841117c527f3328402be2b5e3e7119639ea0e497c6181621bfcad89a3493 + +RC_multi: +Proof size: 5.21 KB +Proof hash: c1b8b00e15eda5dc92b6161bc30a7290268d5694e6b274e79132c0246e693b98 +Prover_pp hash: 2c4d4cb9a62637a4247d4d4d0264c287e17173259f7d199880ebf18ae835b1e9 +Verifier_pp hash: c647c30e4a9584774a2020d9feafecdd70c0e74300cb93ef18383998711bd59e KZG.qc: Proof size: 1.49 KB diff --git a/src/lib_plonk/test/test_range_checks.ml b/src/lib_plonk/test/test_range_checks.ml index 0f953450eae36cb62a208d0419e81d9dcd142d94..fc88aa8219f77b5f4d44ade2cb75d8c754c4c9a0 100644 --- a/src/lib_plonk/test/test_range_checks.ml +++ b/src/lib_plonk/test/test_range_checks.ml @@ -34,7 +34,7 @@ module External (PC : Polynomial_commitment.S) = struct () in let inputs = General.witness in - H.test_circuit ~name:"Range_Checks_single" ~zero_knowledge circuit inputs ; + H.test_circuit ~name:"RC_single" ~zero_knowledge circuit inputs ; let circuit = Plonk.Circuit.make ~wires @@ -43,15 +43,9 @@ module External (PC : Polynomial_commitment.S) = struct ~range_checks:([1; 3; 4; 6], 2) () in - try - H.test_circuit - ~name:"Range_Checks_single_wrong" - ~zero_knowledge - circuit - inputs + try H.test_circuit ~name:"RC_single_wrong" ~zero_knowledge circuit inputs with Plonk.Main_protocol.Rest_not_null _ -> () - (* This test does not work since several proofs are not supported yet *) let test_range_checks_multi ~zero_knowledge () = let wires = Array.map Array.to_list General.circuit.wires in let gates = SMap.map Array.to_list General.circuit.gates in @@ -79,7 +73,7 @@ module External (PC : Polynomial_commitment.S) = struct SMap.of_list [("circuit1", [witness; witness]); ("circuit2", [witness])] in - H.test_circuits ~name:"Range_Checks_multi" ~zero_knowledge circuits inputs ; + H.test_circuits ~name:"RC_multi" ~zero_knowledge circuits inputs ; let circuit3 = Plonk.Circuit.make @@ -91,18 +85,13 @@ module External (PC : Polynomial_commitment.S) = struct in let circuits = SMap.add_unique "circuit3" (circuit3, 1) circuits in let inputs = SMap.add_unique "circuit3" [witness] inputs in - try - H.test_circuits - ~name:"Range_Checks_multi_wrong" - ~zero_knowledge - circuits - inputs + try H.test_circuits ~name:"RC_multi_wrong" ~zero_knowledge circuits inputs with Plonk.Main_protocol.Rest_not_null _ -> () let tests_quick pc_name = [ - (pc_name ^ ".Range_Checks_single", test_range_checks_single) - (* (pc_name ^ ".Range_Checks_multi", test_range_checks_multi); *); + (pc_name ^ ".RC_single", test_range_checks_single); + (pc_name ^ ".RC_multi", test_range_checks_multi); ] end