From 8e5a691a2c2810035a7ca9ef555f1fdc14b4be47 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Tue, 11 Mar 2025 13:55:19 +0100 Subject: [PATCH 1/5] Crypto: rename aggregate_lc -> aggregate_weighted --- src/lib_bls12_381_signature/bls12_381_signature.ml | 4 ++-- src/lib_bls12_381_signature/bls12_381_signature.mli | 12 ++++++------ src/lib_crypto/aggregate_signature.ml | 4 ++-- src/lib_crypto/bls.ml | 4 ++-- src/lib_crypto/s.ml | 4 ++-- src/lib_protocol_environment/environment_V15.ml | 2 +- src/lib_protocol_environment/sigs/v15.ml | 2 +- src/lib_protocol_environment/sigs/v15/s.mli | 2 +- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/lib_bls12_381_signature/bls12_381_signature.ml b/src/lib_bls12_381_signature/bls12_381_signature.ml index 75406dedc41a..8ec2afc7292d 100644 --- a/src/lib_bls12_381_signature/bls12_381_signature.ml +++ b/src/lib_bls12_381_signature/bls12_381_signature.ml @@ -265,7 +265,7 @@ module MinPk = struct Bls12_381.G1.to_compressed_bytes res) pks - let aggregate_public_key_lc_opt pks_with_weights = + let aggregate_public_key_weighted_opt pks_with_weights = let pks_opts = List.map (fun (w, pk) -> (w, Bls12_381.G1.of_compressed_bytes_opt pk)) @@ -594,7 +594,7 @@ module MinSig = struct Bls12_381.G2.to_compressed_bytes res) pks - let aggregate_public_key_lc_opt pks_with_weights = + let aggregate_public_key_weighted_opt pks_with_weights = let pks_opts = List.map (fun (w, pk) -> (w, Bls12_381.G2.of_compressed_bytes_opt pk)) diff --git a/src/lib_bls12_381_signature/bls12_381_signature.mli b/src/lib_bls12_381_signature/bls12_381_signature.mli index a81130d79fd3..aa25b6a88384 100644 --- a/src/lib_bls12_381_signature/bls12_381_signature.mli +++ b/src/lib_bls12_381_signature/bls12_381_signature.mli @@ -122,9 +122,9 @@ module MinPk : sig points are in G1. *) val aggregate_public_key_opt : ?subgroup_check:bool -> pk list -> pk option - (** [aggregate_public_key_lc_opt [(w_1, pk_1);(w_2, pk_2);...]] aggregates the public - keys [w_i] * [pk_i]. *) - val aggregate_public_key_lc_opt : (Z.t * pk) list -> pk option + (** [aggregate_public_key_weighted_opt [(w_1, pk_1);(w_2, pk_2);...]] aggregates the public + keys [pk_i] multiplied by their weights [w_i], i.e it returns the sum of [w_i * pk_i]. *) + val aggregate_public_key_weighted_opt : (Z.t * pk) list -> pk option (** Basic scheme described in {{:https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-04#section-3.1} @@ -313,9 +313,9 @@ module MinSig : sig points are in G2. *) val aggregate_public_key_opt : ?subgroup_check:bool -> pk list -> pk option - (** [aggregate_public_key_lc_opt [(w_1, pk_1);(w_2, pk_2);...]] aggregates the public - keys [w_i] * [pk_i]. *) - val aggregate_public_key_lc_opt : (Z.t * pk) list -> pk option + (** [aggregate_public_key_weighted_opt [(w_1, pk_1);(w_2, pk_2);...]] aggregates the public + keys [pk_i] multiplied by their weights [w_i], i.e it returns the sum of [w_i * pk_i]. *) + val aggregate_public_key_weighted_opt : (Z.t * pk) list -> pk option (** Basic scheme described in {{:https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-04#section-3.1} diff --git a/src/lib_crypto/aggregate_signature.ml b/src/lib_crypto/aggregate_signature.ml index 6af35fdbba07..0fa7e8bb46b8 100644 --- a/src/lib_crypto/aggregate_signature.ml +++ b/src/lib_crypto/aggregate_signature.ml @@ -519,7 +519,7 @@ let aggregate_public_key_opt ?subgroup_check pks = |> Bls.aggregate_public_key_opt ?subgroup_check |> Option.map (fun s -> Public_key.Bls12_381 s) -let aggregate_public_key_lc_opt pks_with_weights = +let aggregate_public_key_weighted_opt pks_with_weights = List.map (function w, Public_key.Bls12_381 s -> (w, s)) pks_with_weights - |> Bls.aggregate_public_key_lc_opt + |> Bls.aggregate_public_key_weighted_opt |> Option.map (fun s -> Public_key.Bls12_381 s) diff --git a/src/lib_crypto/bls.ml b/src/lib_crypto/bls.ml index e16793c40ef8..5efc169244cf 100644 --- a/src/lib_crypto/bls.ml +++ b/src/lib_crypto/bls.ml @@ -392,8 +392,8 @@ let aggregate_signature_opt = Bls12_381_signature.MinPk.aggregate_signature_opt let aggregate_public_key_opt = Bls12_381_signature.MinPk.aggregate_public_key_opt -let aggregate_public_key_lc_opt = - Bls12_381_signature.MinPk.aggregate_public_key_lc_opt +let aggregate_public_key_weighted_opt = + Bls12_381_signature.MinPk.aggregate_public_key_weighted_opt module Primitive = struct include Bls12_381 diff --git a/src/lib_crypto/s.ml b/src/lib_crypto/s.ml index 49caeb494d03..396173e52bb2 100644 --- a/src/lib_crypto/s.ml +++ b/src/lib_crypto/s.ml @@ -458,9 +458,9 @@ module type AGGREGATE_SIGNATURE = sig ?subgroup_check:bool -> Public_key.t list -> Public_key.t option (** [aggregate_public_key_lc_opt pk_with_weights_list] creates an aggregated public - key as a linear combination from the list of public_keys and their weights in + key as a weighted sum of the list of public keys and their weights in [pk_with_weights_list]. *) - val aggregate_public_key_lc_opt : + val aggregate_public_key_weighted_opt : (Z.t * Public_key.t) list -> Public_key.t option end diff --git a/src/lib_protocol_environment/environment_V15.ml b/src/lib_protocol_environment/environment_V15.ml index b733e12a683e..4906ff5f5502 100644 --- a/src/lib_protocol_environment/environment_V15.ml +++ b/src/lib_protocol_environment/environment_V15.ml @@ -532,7 +532,7 @@ struct val aggregate_public_key_opt : ?subgroup_check:bool -> Public_key.t list -> Public_key.t option - val aggregate_public_key_lc_opt : + val aggregate_public_key_weighted_opt : (Z.t * Public_key.t) list -> Public_key.t option end diff --git a/src/lib_protocol_environment/sigs/v15.ml b/src/lib_protocol_environment/sigs/v15.ml index cb71c6779675..ab4c1d1846e9 100644 --- a/src/lib_protocol_environment/sigs/v15.ml +++ b/src/lib_protocol_environment/sigs/v15.ml @@ -9476,7 +9476,7 @@ module type AGGREGATE_SIGNATURE = sig val aggregate_public_key_opt : ?subgroup_check:bool -> Public_key.t list -> Public_key.t option - val aggregate_public_key_lc_opt : + val aggregate_public_key_weighted_opt : (Z.t * Public_key.t) list -> Public_key.t option end diff --git a/src/lib_protocol_environment/sigs/v15/s.mli b/src/lib_protocol_environment/sigs/v15/s.mli index 5c4b2bff7c23..75bde02df999 100644 --- a/src/lib_protocol_environment/sigs/v15/s.mli +++ b/src/lib_protocol_environment/sigs/v15/s.mli @@ -245,7 +245,7 @@ module type AGGREGATE_SIGNATURE = sig val aggregate_public_key_opt : ?subgroup_check:bool -> Public_key.t list -> Public_key.t option - val aggregate_public_key_lc_opt : + val aggregate_public_key_weighted_opt : (Z.t * Public_key.t) list -> Public_key.t option end -- GitLab From 9de9e88064098aeb571f71ddc5b3ec02dc9358ef Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Thu, 6 Mar 2025 12:05:03 +0100 Subject: [PATCH 2/5] Bls: use pippenger for aggregate_weighted_lc Co-authored-by: Marina Polubelova (@polubelova) --- .../bls12_381_signature.ml | 52 ++++++++----------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/src/lib_bls12_381_signature/bls12_381_signature.ml b/src/lib_bls12_381_signature/bls12_381_signature.ml index 8ec2afc7292d..601f20298e74 100644 --- a/src/lib_bls12_381_signature/bls12_381_signature.ml +++ b/src/lib_bls12_381_signature/bls12_381_signature.ml @@ -266,22 +266,18 @@ module MinPk = struct pks let aggregate_public_key_weighted_opt pks_with_weights = - let pks_opts = - List.map - (fun (w, pk) -> (w, Bls12_381.G1.of_compressed_bytes_opt pk)) - pks_with_weights + let weights, pks = List.split pks_with_weights in + let scalars = List.map Bls12_381.Fr.of_z weights |> Array.of_list in + let pks = + Bls12_381.G1.affine_array_of_compressed_bytes_opt + ~subgroup_check:true + (Array.of_list pks) in - let pks_are_ok = List.for_all (fun (_, pk) -> Option.is_some pk) pks_opts in - if not pks_are_ok then None - else - let pks = - List.map - (fun (w, pk) -> - Bls12_381.G1.mul (Option.get pk) (Bls12_381.Fr.of_z w)) - pks_opts - in - let aggregated_pk = Bls12_381.G1.add_bulk pks in - Some (Bls12_381.G1.to_compressed_bytes aggregated_pk) + Option.map + (fun pks -> + let res = Bls12_381.G1.pippenger_with_affine_array pks scalars in + Bls12_381.G1.to_compressed_bytes res) + pks let core_aggregate_verify pks_with_msgs aggregated_signature ciphersuite = let rec aux aggregated_signature pks_with_msgs ctxt = @@ -595,22 +591,18 @@ module MinSig = struct pks let aggregate_public_key_weighted_opt pks_with_weights = - let pks_opts = - List.map - (fun (w, pk) -> (w, Bls12_381.G2.of_compressed_bytes_opt pk)) - pks_with_weights + let weights, pks = List.split pks_with_weights in + let scalars = List.map Bls12_381.Fr.of_z weights |> Array.of_list in + let pks = + Bls12_381.G2.affine_array_of_compressed_bytes_opt + ~subgroup_check:true + (Array.of_list pks) in - let pks_are_ok = List.for_all (fun (_, pk) -> Option.is_some pk) pks_opts in - if not pks_are_ok then None - else - let pks = - List.map - (fun (w, pk) -> - Bls12_381.G2.mul (Option.get pk) (Bls12_381.Fr.of_z w)) - pks_opts - in - let aggregated_pk = Bls12_381.G2.add_bulk pks in - Some (Bls12_381.G2.to_compressed_bytes aggregated_pk) + Option.map + (fun pks -> + let res = Bls12_381.G2.pippenger_with_affine_array pks scalars in + Bls12_381.G2.to_compressed_bytes res) + pks let core_aggregate_verify pks_with_msgs aggregated_signature ciphersuite = let rec aux aggregated_signature pks_with_msgs ctxt = -- GitLab From 7bca1d185141268d0675f58a5f5f5eccd9aa8c61 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Thu, 6 Mar 2025 12:17:29 +0100 Subject: [PATCH 3/5] Bls: use subgroup_check for aggregate_weighted_lc --- src/lib_bls12_381_signature/bls12_381_signature.ml | 10 ++++++---- src/lib_bls12_381_signature/bls12_381_signature.mli | 6 ++++-- src/lib_crypto/aggregate_signature.ml | 4 ++-- src/lib_crypto/s.ml | 2 +- src/lib_protocol_environment/environment_V15.ml | 2 +- src/lib_protocol_environment/sigs/v15.ml | 2 +- src/lib_protocol_environment/sigs/v15/s.mli | 2 +- 7 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/lib_bls12_381_signature/bls12_381_signature.ml b/src/lib_bls12_381_signature/bls12_381_signature.ml index 601f20298e74..1d78a37eaa1b 100644 --- a/src/lib_bls12_381_signature/bls12_381_signature.ml +++ b/src/lib_bls12_381_signature/bls12_381_signature.ml @@ -265,12 +265,13 @@ module MinPk = struct Bls12_381.G1.to_compressed_bytes res) pks - let aggregate_public_key_weighted_opt pks_with_weights = + let aggregate_public_key_weighted_opt ?(subgroup_check = true) + pks_with_weights = let weights, pks = List.split pks_with_weights in let scalars = List.map Bls12_381.Fr.of_z weights |> Array.of_list in let pks = Bls12_381.G1.affine_array_of_compressed_bytes_opt - ~subgroup_check:true + ~subgroup_check (Array.of_list pks) in Option.map @@ -590,12 +591,13 @@ module MinSig = struct Bls12_381.G2.to_compressed_bytes res) pks - let aggregate_public_key_weighted_opt pks_with_weights = + let aggregate_public_key_weighted_opt ?(subgroup_check = true) + pks_with_weights = let weights, pks = List.split pks_with_weights in let scalars = List.map Bls12_381.Fr.of_z weights |> Array.of_list in let pks = Bls12_381.G2.affine_array_of_compressed_bytes_opt - ~subgroup_check:true + ~subgroup_check (Array.of_list pks) in Option.map diff --git a/src/lib_bls12_381_signature/bls12_381_signature.mli b/src/lib_bls12_381_signature/bls12_381_signature.mli index aa25b6a88384..4e2137aa9c49 100644 --- a/src/lib_bls12_381_signature/bls12_381_signature.mli +++ b/src/lib_bls12_381_signature/bls12_381_signature.mli @@ -124,7 +124,8 @@ module MinPk : sig (** [aggregate_public_key_weighted_opt [(w_1, pk_1);(w_2, pk_2);...]] aggregates the public keys [pk_i] multiplied by their weights [w_i], i.e it returns the sum of [w_i * pk_i]. *) - val aggregate_public_key_weighted_opt : (Z.t * pk) list -> pk option + val aggregate_public_key_weighted_opt : + ?subgroup_check:bool -> (Z.t * pk) list -> pk option (** Basic scheme described in {{:https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-04#section-3.1} @@ -315,7 +316,8 @@ module MinSig : sig (** [aggregate_public_key_weighted_opt [(w_1, pk_1);(w_2, pk_2);...]] aggregates the public keys [pk_i] multiplied by their weights [w_i], i.e it returns the sum of [w_i * pk_i]. *) - val aggregate_public_key_weighted_opt : (Z.t * pk) list -> pk option + val aggregate_public_key_weighted_opt : + ?subgroup_check:bool -> (Z.t * pk) list -> pk option (** Basic scheme described in {{:https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-04#section-3.1} diff --git a/src/lib_crypto/aggregate_signature.ml b/src/lib_crypto/aggregate_signature.ml index 0fa7e8bb46b8..fb5d72698486 100644 --- a/src/lib_crypto/aggregate_signature.ml +++ b/src/lib_crypto/aggregate_signature.ml @@ -519,7 +519,7 @@ let aggregate_public_key_opt ?subgroup_check pks = |> Bls.aggregate_public_key_opt ?subgroup_check |> Option.map (fun s -> Public_key.Bls12_381 s) -let aggregate_public_key_weighted_opt pks_with_weights = +let aggregate_public_key_weighted_opt ?subgroup_check pks_with_weights = List.map (function w, Public_key.Bls12_381 s -> (w, s)) pks_with_weights - |> Bls.aggregate_public_key_weighted_opt + |> Bls.aggregate_public_key_weighted_opt ?subgroup_check |> Option.map (fun s -> Public_key.Bls12_381 s) diff --git a/src/lib_crypto/s.ml b/src/lib_crypto/s.ml index 396173e52bb2..c16dd3787a22 100644 --- a/src/lib_crypto/s.ml +++ b/src/lib_crypto/s.ml @@ -461,7 +461,7 @@ module type AGGREGATE_SIGNATURE = sig key as a weighted sum of the list of public keys and their weights in [pk_with_weights_list]. *) val aggregate_public_key_weighted_opt : - (Z.t * Public_key.t) list -> Public_key.t option + ?subgroup_check:bool -> (Z.t * Public_key.t) list -> Public_key.t option end module type SPLIT_SIGNATURE = sig diff --git a/src/lib_protocol_environment/environment_V15.ml b/src/lib_protocol_environment/environment_V15.ml index 4906ff5f5502..9a7cdec48486 100644 --- a/src/lib_protocol_environment/environment_V15.ml +++ b/src/lib_protocol_environment/environment_V15.ml @@ -533,7 +533,7 @@ struct ?subgroup_check:bool -> Public_key.t list -> Public_key.t option val aggregate_public_key_weighted_opt : - (Z.t * Public_key.t) list -> Public_key.t option + ?subgroup_check:bool -> (Z.t * Public_key.t) list -> Public_key.t option end module type SPLIT_SIGNATURE = sig diff --git a/src/lib_protocol_environment/sigs/v15.ml b/src/lib_protocol_environment/sigs/v15.ml index ab4c1d1846e9..832e9e0bf637 100644 --- a/src/lib_protocol_environment/sigs/v15.ml +++ b/src/lib_protocol_environment/sigs/v15.ml @@ -9477,7 +9477,7 @@ module type AGGREGATE_SIGNATURE = sig ?subgroup_check:bool -> Public_key.t list -> Public_key.t option val aggregate_public_key_weighted_opt : - (Z.t * Public_key.t) list -> Public_key.t option + ?subgroup_check:bool -> (Z.t * Public_key.t) list -> Public_key.t option end module type SPLIT_SIGNATURE = sig diff --git a/src/lib_protocol_environment/sigs/v15/s.mli b/src/lib_protocol_environment/sigs/v15/s.mli index 75bde02df999..8c72e0c17722 100644 --- a/src/lib_protocol_environment/sigs/v15/s.mli +++ b/src/lib_protocol_environment/sigs/v15/s.mli @@ -246,7 +246,7 @@ module type AGGREGATE_SIGNATURE = sig ?subgroup_check:bool -> Public_key.t list -> Public_key.t option val aggregate_public_key_weighted_opt : - (Z.t * Public_key.t) list -> Public_key.t option + ?subgroup_check:bool -> (Z.t * Public_key.t) list -> Public_key.t option end module type SPLIT_SIGNATURE = sig -- GitLab From 34db6528f1a00cbc1a21952b3c0be064b22f94e1 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Tue, 11 Mar 2025 14:39:52 +0100 Subject: [PATCH 4/5] Bls: add weighted aggregation for signatures --- .../bls12_381_signature.ml | 30 +++++++++++++++++++ .../bls12_381_signature.mli | 20 +++++++++++-- src/lib_crypto/aggregate_signature.ml | 15 ++++++++++ src/lib_crypto/bls.ml | 3 ++ src/lib_crypto/s.ml | 20 +++++++++---- .../environment_V15.ml | 3 ++ src/lib_protocol_environment/sigs/v15.ml | 3 ++ src/lib_protocol_environment/sigs/v15/s.mli | 3 ++ 8 files changed, 89 insertions(+), 8 deletions(-) diff --git a/src/lib_bls12_381_signature/bls12_381_signature.ml b/src/lib_bls12_381_signature/bls12_381_signature.ml index 1d78a37eaa1b..d126de0708fd 100644 --- a/src/lib_bls12_381_signature/bls12_381_signature.ml +++ b/src/lib_bls12_381_signature/bls12_381_signature.ml @@ -253,6 +253,21 @@ module MinPk = struct Bls12_381.G2.to_compressed_bytes res) signatures + let aggregate_signature_weighted_opt ?(subgroup_check = true) + signatures_with_weights = + let weights, signatures = List.split signatures_with_weights in + let scalars = List.map Bls12_381.Fr.of_z weights |> Array.of_list in + let signatures = + Bls12_381.G2.affine_array_of_compressed_bytes_opt + ~subgroup_check + (Array.of_list signatures) + in + Option.map + (fun signatures -> + let res = Bls12_381.G2.pippenger_with_affine_array signatures scalars in + Bls12_381.G2.to_compressed_bytes res) + signatures + let aggregate_public_key_opt ?(subgroup_check = true) pks = let pks = Bls12_381.G1.affine_array_of_compressed_bytes_opt @@ -579,6 +594,21 @@ module MinSig = struct Bls12_381.G1.to_compressed_bytes res) signatures + let aggregate_signature_weighted_opt ?(subgroup_check = true) + signatures_with_weights = + let weights, signatures = List.split signatures_with_weights in + let scalars = List.map Bls12_381.Fr.of_z weights |> Array.of_list in + let signatures = + Bls12_381.G1.affine_array_of_compressed_bytes_opt + ~subgroup_check + (Array.of_list signatures) + in + Option.map + (fun signatures -> + let res = Bls12_381.G1.pippenger_with_affine_array signatures scalars in + Bls12_381.G1.to_compressed_bytes res) + signatures + let aggregate_public_key_opt ?(subgroup_check = true) pks = let pks = Bls12_381.G2.affine_array_of_compressed_bytes_opt diff --git a/src/lib_bls12_381_signature/bls12_381_signature.mli b/src/lib_bls12_381_signature/bls12_381_signature.mli index 4e2137aa9c49..38a147278e3f 100644 --- a/src/lib_bls12_381_signature/bls12_381_signature.mli +++ b/src/lib_bls12_381_signature/bls12_381_signature.mli @@ -117,13 +117,21 @@ module MinPk : sig Return [None] if [INVALID] is expected in the specification *) val aggregate_signature_opt : signature list -> signature option + (** [aggregate_signature_weighted_opt [(w_1, s_1);(w_1, s_2);...]] aggregates the signatures + [s_i] multiplied by their weights [w_i], i.e it returns the sum of [w_i * s_i]. + Return [None] if deserialization of signatures fails. If [subgroup_check] is set, the + function also checks if the points are in G2. *) + val aggregate_signature_weighted_opt : + ?subgroup_check:bool -> (Z.t * signature) list -> signature option + (** [aggregate_public_key_opt ?subgroup_check pks] aggregates the public keys [pks]. If [subgroup_check] is set, the function also checks if the points are in G1. *) val aggregate_public_key_opt : ?subgroup_check:bool -> pk list -> pk option (** [aggregate_public_key_weighted_opt [(w_1, pk_1);(w_2, pk_2);...]] aggregates the public - keys [pk_i] multiplied by their weights [w_i], i.e it returns the sum of [w_i * pk_i]. *) + keys [pk_i] multiplied by their weights [w_i], i.e it returns the sum of [w_i * pk_i]. + If [subgroup_check] is set, the function also checks if the points are in G1. *) val aggregate_public_key_weighted_opt : ?subgroup_check:bool -> (Z.t * pk) list -> pk option @@ -309,13 +317,21 @@ module MinSig : sig Return [None] if [INVALID] is expected in the specification *) val aggregate_signature_opt : signature list -> signature option + (** [aggregate_signature_weighted_opt [(w_1, s_1);(w_1, s_2);...]] aggregates the signatures + [s_i] multiplied by their weights [w_i], i.e it returns the sum of [w_i * s_i]. + Return [None] if deserialization of signatures fails. If [subgroup_check] is set, the + function also checks if the points are in G1. *) + val aggregate_signature_weighted_opt : + ?subgroup_check:bool -> (Z.t * signature) list -> signature option + (** [aggregate_public_key_opt ?subgroup_check pks] aggregates the public keys [pks]. If [subgroup_check] is set, the function also checks if the points are in G2. *) val aggregate_public_key_opt : ?subgroup_check:bool -> pk list -> pk option (** [aggregate_public_key_weighted_opt [(w_1, pk_1);(w_2, pk_2);...]] aggregates the public - keys [pk_i] multiplied by their weights [w_i], i.e it returns the sum of [w_i * pk_i]. *) + keys [pk_i] multiplied by their weights [w_i], i.e it returns the sum of [w_i * pk_i]. + If [subgroup_check] is set, the function also checks if the points are in G2. *) val aggregate_public_key_weighted_opt : ?subgroup_check:bool -> (Z.t * pk) list -> pk option diff --git a/src/lib_crypto/aggregate_signature.ml b/src/lib_crypto/aggregate_signature.ml index fb5d72698486..bd03e53b8ea8 100644 --- a/src/lib_crypto/aggregate_signature.ml +++ b/src/lib_crypto/aggregate_signature.ml @@ -514,6 +514,21 @@ let aggregate_signature_opt signatures = |> Option.map (fun s -> Bls12_381 s) | Error _ -> None +let aggregate_signature_weighted_opt ?subgroup_check signatures_with_weights = + let open Result_syntax in + let aux acc (w, s) = + match s with + | Bls12_381 s -> return @@ ((w, s) :: acc) + | Unknown s -> + let* s = Bls.of_bytes s in + return ((w, s) :: acc) + in + match List.fold_left_e aux [] signatures_with_weights with + | Ok signatures -> + Bls.aggregate_signature_weighted_opt ?subgroup_check signatures + |> Option.map (fun s -> Bls12_381 s) + | Error _ -> None + let aggregate_public_key_opt ?subgroup_check pks = List.map (function Public_key.Bls12_381 s -> s) pks |> Bls.aggregate_public_key_opt ?subgroup_check diff --git a/src/lib_crypto/bls.ml b/src/lib_crypto/bls.ml index 5efc169244cf..dbaaf15b6a3b 100644 --- a/src/lib_crypto/bls.ml +++ b/src/lib_crypto/bls.ml @@ -389,6 +389,9 @@ let aggregate_check pk_msg_list signature = let aggregate_signature_opt = Bls12_381_signature.MinPk.aggregate_signature_opt +let aggregate_signature_weighted_opt = + Bls12_381_signature.MinPk.aggregate_signature_weighted_opt + let aggregate_public_key_opt = Bls12_381_signature.MinPk.aggregate_public_key_opt diff --git a/src/lib_crypto/s.ml b/src/lib_crypto/s.ml index c16dd3787a22..6e830427caaf 100644 --- a/src/lib_crypto/s.ml +++ b/src/lib_crypto/s.ml @@ -451,15 +451,23 @@ module type AGGREGATE_SIGNATURE = sig the list of signatures [sig_list]. *) val aggregate_signature_opt : t list -> t option - (** [aggregate_public_key_opt pk_list] creates an aggregated public key using - the list of public_keys [pk_list]. If [subgroup_check] is set, the function - also checks if the points are in the prime subgroup. *) + (** [aggregate_signature_weighted_opt [(w_1, s_1);(w_1, s_2);...]] aggregates the signatures + [s_i] multiplied by their weights [w_i], i.e it returns the sum of [w_i * s_i]. + Return [None] if deserialization of signatures fails. If [subgroup_check] is set, the + function also checks if the points are in the prime subgroup. *) + val aggregate_signature_weighted_opt : + ?subgroup_check:bool -> (Z.t * t) list -> t option + + (** [aggregate_public_key_opt ?subgroup_check pks] aggregates the public keys + [pks]. If [subgroup_check] is set, the function also checks if the + points are in the prime subgroup. *) val aggregate_public_key_opt : ?subgroup_check:bool -> Public_key.t list -> Public_key.t option - (** [aggregate_public_key_lc_opt pk_with_weights_list] creates an aggregated public - key as a weighted sum of the list of public keys and their weights in - [pk_with_weights_list]. *) + (** [aggregate_public_key_weighted_opt [(w_1, pk_1);(w_2, pk_2);...]] aggregates the public + keys [pk_i] multiplied by their weights [w_i], i.e it returns the sum of [w_i * pk_i]. + If [subgroup_check] is set, the function also checks if the points are in the + prime subgroup. *) val aggregate_public_key_weighted_opt : ?subgroup_check:bool -> (Z.t * Public_key.t) list -> Public_key.t option end diff --git a/src/lib_protocol_environment/environment_V15.ml b/src/lib_protocol_environment/environment_V15.ml index 9a7cdec48486..2ebf5c7e6d34 100644 --- a/src/lib_protocol_environment/environment_V15.ml +++ b/src/lib_protocol_environment/environment_V15.ml @@ -529,6 +529,9 @@ struct val aggregate_signature_opt : t list -> t option + val aggregate_signature_weighted_opt : + ?subgroup_check:bool -> (Z.t * t) list -> t option + val aggregate_public_key_opt : ?subgroup_check:bool -> Public_key.t list -> Public_key.t option diff --git a/src/lib_protocol_environment/sigs/v15.ml b/src/lib_protocol_environment/sigs/v15.ml index 832e9e0bf637..ac1cb4a8e523 100644 --- a/src/lib_protocol_environment/sigs/v15.ml +++ b/src/lib_protocol_environment/sigs/v15.ml @@ -9473,6 +9473,9 @@ module type AGGREGATE_SIGNATURE = sig val aggregate_signature_opt : t list -> t option + val aggregate_signature_weighted_opt : + ?subgroup_check:bool -> (Z.t * t) list -> t option + val aggregate_public_key_opt : ?subgroup_check:bool -> Public_key.t list -> Public_key.t option diff --git a/src/lib_protocol_environment/sigs/v15/s.mli b/src/lib_protocol_environment/sigs/v15/s.mli index 8c72e0c17722..66d5ea6ac9af 100644 --- a/src/lib_protocol_environment/sigs/v15/s.mli +++ b/src/lib_protocol_environment/sigs/v15/s.mli @@ -242,6 +242,9 @@ module type AGGREGATE_SIGNATURE = sig val aggregate_signature_opt : t list -> t option + val aggregate_signature_weighted_opt : + ?subgroup_check:bool -> (Z.t * t) list -> t option + val aggregate_public_key_opt : ?subgroup_check:bool -> Public_key.t list -> Public_key.t option -- GitLab From 142286c9b412d136455c0176f2891f808bdf27c9 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Thu, 6 Mar 2025 16:15:32 +0100 Subject: [PATCH 5/5] Crypto: add tests for pop aggregation Deactivated other bls test: depends on Aug for check, but generates pop keys. --- src/lib_crypto/test/test_prop_signature.ml | 76 ++++++++++++++++++++-- 1 file changed, 71 insertions(+), 5 deletions(-) diff --git a/src/lib_crypto/test/test_prop_signature.ml b/src/lib_crypto/test/test_prop_signature.ml index 04444581d6bb..c208243f45ea 100644 --- a/src/lib_crypto/test/test_prop_signature.ml +++ b/src/lib_crypto/test/test_prop_signature.ml @@ -95,7 +95,7 @@ struct [X.check] when using the corresponding key. It then tests that the aggregation of all these signatures obtained using [X.aggregate_signature_opt] is accepted by [X.aggregate_check]. *) - let test_prop_sign_check + let test_prop_aug_sign_check ( (seed1, msg1, watermark1), (seed2, msg2, watermark2), (seed3, msg3, watermark3) ) = @@ -125,7 +125,7 @@ struct && X.check_aug ?watermark:watermark3 pk3 signed3 msg3 && is_valid_aggregated_sign - let test_prop_sign_check = + let test_prop_aug_sign_check = let gen = let open Gen in let+ seed1 = string_size (pure 32) >|= Bytes.of_string @@ -147,12 +147,78 @@ struct (option Bytes.unsafe_to_string)) in Test.make - ~name:("Aggregate_signature_" ^ Desc.name ^ "_sign_check") + ~name:("Aggregate_signature_" ^ Desc.name ^ "_aug_sign_check") ~print:(Print.triple print_param print_param print_param) gen - test_prop_sign_check + test_prop_aug_sign_check - let tests = [test_prop_sign_check] + let test_prop_pop_sign_check ~subgroup_check + (((seed1, weight1), (seed2, weight2), (seed3, weight3)), watermark, msg) = + let _, pk1, sk1 = X.generate_key ~seed:seed1 () in + let _, pk2, sk2 = X.generate_key ~seed:seed2 () in + let _, pk3, sk3 = X.generate_key ~seed:seed3 () in + let watermark = Option.map X.watermark_of_bytes watermark in + let signed1 = X.sign ?watermark sk1 msg in + let signed2 = X.sign ?watermark sk2 msg in + let signed3 = X.sign ?watermark sk3 msg in + let is_ok_aggregate_pk = + X.aggregate_public_key_opt ~subgroup_check [pk1; pk2; pk3] |> function + | None -> false + | Some pk_agg -> ( + X.aggregate_signature_opt [signed1; signed2; signed3] |> function + | None -> false + | Some signed_agg -> X.check ?watermark pk_agg signed_agg msg) + in + let is_ok_aggregate_pk_weighted = + X.aggregate_public_key_weighted_opt + ~subgroup_check + [(weight1, pk1); (weight2, pk2); (weight3, pk3)] + |> function + | None -> false + | Some pk_agg -> ( + X.aggregate_signature_weighted_opt + [(weight1, signed1); (weight2, signed2); (weight3, signed3)] + |> function + | None -> false + | Some signed_agg -> X.check ?watermark pk_agg signed_agg msg) + in + X.check ?watermark pk1 signed1 msg + && X.check ?watermark pk2 signed2 msg + && X.check ?watermark pk3 signed3 msg + && is_ok_aggregate_pk && is_ok_aggregate_pk_weighted + + let test_prop_pop_sign_check ~subgroup_check = + let gen = + let open Gen in + let+ seed1 = string_size (pure 32) >|= Bytes.of_string + and+ seed2 = string_size (pure 32) >|= Bytes.of_string + and+ seed3 = string_size (pure 32) >|= Bytes.of_string + and+ weight1 = int >|= Z.of_int + and+ weight2 = int >|= Z.of_int + and+ weight3 = int >|= Z.of_int + and+ msg = string >|= Bytes.of_string + and+ wm = gen_watermark |> option in + (((seed1, weight1), (seed2, weight2), (seed3, weight3)), wm, msg) + in + let print_param = Print.(pair Bytes.unsafe_to_string Z.to_string) in + Test.make + ~name: + ("Aggregate_signature_" ^ Desc.name ^ "_pop_sign_check" + ^ if subgroup_check then "" else "_fast") + ~print: + Print.( + triple + (triple print_param print_param print_param) + (option Bytes.unsafe_to_string) + Bytes.unsafe_to_string) + gen + (test_prop_pop_sign_check ~subgroup_check) + + let tests = + [ + test_prop_pop_sign_check ~subgroup_check:true; + test_prop_pop_sign_check ~subgroup_check:false; + ] end (** Test: instantiate Signature_Properties over Signature -- GitLab