From 0e3fc39dce302d137f6dc7779a073db36a116198 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Wed, 5 Mar 2025 16:51:42 +0100 Subject: [PATCH 1/3] Proto/Env: expose aggregate_public_key_opt --- src/lib_bls12_381_signature/bls12_381_signature.mli | 10 ++++++++++ src/lib_crypto/aggregate_signature.ml | 5 +++++ src/lib_crypto/bls.ml | 3 +++ src/lib_crypto/s.ml | 10 ++++++++-- src/lib_protocol_environment/environment_V15.ml | 3 +++ src/lib_protocol_environment/sigs/v15.ml | 3 +++ src/lib_protocol_environment/sigs/v15/s.mli | 3 +++ 7 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/lib_bls12_381_signature/bls12_381_signature.mli b/src/lib_bls12_381_signature/bls12_381_signature.mli index a29bf3573329..75f8b57d8b38 100644 --- a/src/lib_bls12_381_signature/bls12_381_signature.mli +++ b/src/lib_bls12_381_signature/bls12_381_signature.mli @@ -117,6 +117,11 @@ module MinPk : sig Return [None] if [INVALID] is expected in the specification *) val aggregate_signature_opt : 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 + (** Basic scheme described in {{:https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-04#section-3.1} section 3.1} @@ -299,6 +304,11 @@ module MinSig : sig Return [None] if [INVALID] is expected in the specification *) val aggregate_signature_opt : 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 + (** Basic scheme described in {{:https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-04#section-3.1} section 3.1} diff --git a/src/lib_crypto/aggregate_signature.ml b/src/lib_crypto/aggregate_signature.ml index e29e031c012f..6d0288450d78 100644 --- a/src/lib_crypto/aggregate_signature.ml +++ b/src/lib_crypto/aggregate_signature.ml @@ -513,3 +513,8 @@ let aggregate_signature_opt signatures = Bls.aggregate_signature_opt 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 + |> Option.map (fun s -> Public_key.Bls12_381 s) diff --git a/src/lib_crypto/bls.ml b/src/lib_crypto/bls.ml index eecc7872fd7e..16ebc31cfe31 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_public_key_opt = + Bls12_381_signature.MinPk.aggregate_public_key_opt + module Primitive = struct include Bls12_381 diff --git a/src/lib_crypto/s.ml b/src/lib_crypto/s.ml index 8b1ee571d632..41fdb213932e 100644 --- a/src/lib_crypto/s.ml +++ b/src/lib_crypto/s.ml @@ -440,16 +440,22 @@ end module type AGGREGATE_SIGNATURE = sig include SIGNATURE - (** [agregate_check pk_msg_list signature] returns [true] if the [signature] + (** [aggregate_check pk_msg_list signature] returns [true] if the [signature] is a valid aggregate signature of the signatures produced by signing message [msg] (with optional [watermark]) with the secret key of [pk] for each element [(pk, watermark, msg)] of the list [pk_msg_list]. *) val aggregate_check : (Public_key.t * watermark option * bytes) list -> t -> bool - (** [agregate_signature_opt sig_list] creates an aggregated signature using + (** [aggregate_signature_opt sig_list] creates an aggregated signature using 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. *) + val aggregate_public_key_opt : + ?subgroup_check:bool -> 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 72d699524533..c6c647de3955 100644 --- a/src/lib_protocol_environment/environment_V15.ml +++ b/src/lib_protocol_environment/environment_V15.ml @@ -528,6 +528,9 @@ struct (Public_key.t * watermark option * bytes) list -> t -> bool val aggregate_signature_opt : t list -> t option + + val aggregate_public_key_opt : + ?subgroup_check:bool -> 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 d899e0503a56..b33133793d82 100644 --- a/src/lib_protocol_environment/sigs/v15.ml +++ b/src/lib_protocol_environment/sigs/v15.ml @@ -9472,6 +9472,9 @@ module type AGGREGATE_SIGNATURE = sig val aggregate_check : (Public_key.t * watermark option * bytes) list -> t -> bool val aggregate_signature_opt : t list -> t option + + val aggregate_public_key_opt : + ?subgroup_check:bool -> 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 e350f6adc6e1..848df4e6d1f6 100644 --- a/src/lib_protocol_environment/sigs/v15/s.mli +++ b/src/lib_protocol_environment/sigs/v15/s.mli @@ -241,6 +241,9 @@ module type AGGREGATE_SIGNATURE = sig val aggregate_check : (Public_key.t * watermark option * bytes) list -> t -> bool val aggregate_signature_opt : t list -> t option + + val aggregate_public_key_opt : + ?subgroup_check:bool -> Public_key.t list -> Public_key.t option end module type SPLIT_SIGNATURE = sig -- GitLab From 547fddc5497d8b88e63aaeee689e97a805a712d5 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Wed, 5 Mar 2025 17:15:01 +0100 Subject: [PATCH 2/3] Crypto/Bls: implement linear combination pk aggregation --- .../bls12_381_signature.ml | 36 +++++++++++++++++++ .../bls12_381_signature.mli | 8 +++++ 2 files changed, 44 insertions(+) diff --git a/src/lib_bls12_381_signature/bls12_381_signature.ml b/src/lib_bls12_381_signature/bls12_381_signature.ml index ab106572ca77..75406dedc41a 100644 --- a/src/lib_bls12_381_signature/bls12_381_signature.ml +++ b/src/lib_bls12_381_signature/bls12_381_signature.ml @@ -265,6 +265,24 @@ module MinPk = struct Bls12_381.G1.to_compressed_bytes res) pks + let aggregate_public_key_lc_opt pks_with_weights = + let pks_opts = + List.map + (fun (w, pk) -> (w, Bls12_381.G1.of_compressed_bytes_opt pk)) + pks_with_weights + 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) + let core_aggregate_verify pks_with_msgs aggregated_signature ciphersuite = let rec aux aggregated_signature pks_with_msgs ctxt = match pks_with_msgs with @@ -576,6 +594,24 @@ module MinSig = struct Bls12_381.G2.to_compressed_bytes res) pks + let aggregate_public_key_lc_opt pks_with_weights = + let pks_opts = + List.map + (fun (w, pk) -> (w, Bls12_381.G2.of_compressed_bytes_opt pk)) + pks_with_weights + 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) + let core_aggregate_verify pks_with_msgs aggregated_signature ciphersuite = let rec aux aggregated_signature pks_with_msgs ctxt = match pks_with_msgs with diff --git a/src/lib_bls12_381_signature/bls12_381_signature.mli b/src/lib_bls12_381_signature/bls12_381_signature.mli index 75f8b57d8b38..a81130d79fd3 100644 --- a/src/lib_bls12_381_signature/bls12_381_signature.mli +++ b/src/lib_bls12_381_signature/bls12_381_signature.mli @@ -122,6 +122,10 @@ 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 + (** Basic scheme described in {{:https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-04#section-3.1} section 3.1} @@ -309,6 +313,10 @@ 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 + (** Basic scheme described in {{:https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-04#section-3.1} section 3.1} -- GitLab From a88093f498dd41562dd7766adf06605cbb2120f5 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Wed, 5 Mar 2025 17:29:43 +0100 Subject: [PATCH 3/3] Proto/Env: expose aggregate_public_key_lc_opt --- src/lib_crypto/aggregate_signature.ml | 5 +++++ src/lib_crypto/bls.ml | 3 +++ src/lib_crypto/s.ml | 6 ++++++ src/lib_protocol_environment/environment_V15.ml | 3 +++ src/lib_protocol_environment/sigs/v15.ml | 3 +++ src/lib_protocol_environment/sigs/v15/s.mli | 3 +++ 6 files changed, 23 insertions(+) diff --git a/src/lib_crypto/aggregate_signature.ml b/src/lib_crypto/aggregate_signature.ml index 6d0288450d78..6af35fdbba07 100644 --- a/src/lib_crypto/aggregate_signature.ml +++ b/src/lib_crypto/aggregate_signature.ml @@ -518,3 +518,8 @@ 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 |> Option.map (fun s -> Public_key.Bls12_381 s) + +let aggregate_public_key_lc_opt pks_with_weights = + List.map (function w, Public_key.Bls12_381 s -> (w, s)) pks_with_weights + |> Bls.aggregate_public_key_lc_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 16ebc31cfe31..e16793c40ef8 100644 --- a/src/lib_crypto/bls.ml +++ b/src/lib_crypto/bls.ml @@ -392,6 +392,9 @@ 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 + module Primitive = struct include Bls12_381 diff --git a/src/lib_crypto/s.ml b/src/lib_crypto/s.ml index 41fdb213932e..49caeb494d03 100644 --- a/src/lib_crypto/s.ml +++ b/src/lib_crypto/s.ml @@ -456,6 +456,12 @@ module type AGGREGATE_SIGNATURE = sig 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 linear combination from the list of public_keys and their weights in + [pk_with_weights_list]. *) + val aggregate_public_key_lc_opt : + (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 c6c647de3955..b733e12a683e 100644 --- a/src/lib_protocol_environment/environment_V15.ml +++ b/src/lib_protocol_environment/environment_V15.ml @@ -531,6 +531,9 @@ struct val aggregate_public_key_opt : ?subgroup_check:bool -> Public_key.t list -> Public_key.t option + + val aggregate_public_key_lc_opt : + (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 b33133793d82..cb71c6779675 100644 --- a/src/lib_protocol_environment/sigs/v15.ml +++ b/src/lib_protocol_environment/sigs/v15.ml @@ -9475,6 +9475,9 @@ 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 : + (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 848df4e6d1f6..5c4b2bff7c23 100644 --- a/src/lib_protocol_environment/sigs/v15/s.mli +++ b/src/lib_protocol_environment/sigs/v15/s.mli @@ -244,6 +244,9 @@ 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 : + (Z.t * Public_key.t) list -> Public_key.t option end module type SPLIT_SIGNATURE = sig -- GitLab