diff --git a/src/lib_bls12_381_signature/bls12_381_signature.ml b/src/lib_bls12_381_signature/bls12_381_signature.ml index ab106572ca775b79fbbb80bd53c049ff1cffd9db..75406dedc41a95826af31a06d6c5327767f5aa3b 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 a29bf357332946300e2705becfe54d62383e736f..a81130d79fd35cf25ec489da05b1fbb77b463a2c 100644 --- a/src/lib_bls12_381_signature/bls12_381_signature.mli +++ b/src/lib_bls12_381_signature/bls12_381_signature.mli @@ -117,6 +117,15 @@ 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 + + (** [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} @@ -299,6 +308,15 @@ 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 + + (** [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} diff --git a/src/lib_crypto/aggregate_signature.ml b/src/lib_crypto/aggregate_signature.ml index e29e031c012f2a24afe0956fac04a9c893135959..6af35fdbba07d3a1233acaa267515c1c3d50b473 100644 --- a/src/lib_crypto/aggregate_signature.ml +++ b/src/lib_crypto/aggregate_signature.ml @@ -513,3 +513,13 @@ 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) + +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 eecc7872fd7ecbdc626e7362cc4602a29d8cbe52..e16793c40ef854f7361cf26bcdcedefb1d9b59b4 100644 --- a/src/lib_crypto/bls.ml +++ b/src/lib_crypto/bls.ml @@ -389,6 +389,12 @@ 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 + +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 8b1ee571d632153d72b41d8a29cd06c58a0fe5e2..49caeb494d030d6bd289b4c95f9dc3d4c9bd4693 100644 --- a/src/lib_crypto/s.ml +++ b/src/lib_crypto/s.ml @@ -440,16 +440,28 @@ 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 + + (** [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 72d699524533adc856a2662da6e6f17779b66303..b733e12a683eb5990fe38bf8b7e87da973949a57 100644 --- a/src/lib_protocol_environment/environment_V15.ml +++ b/src/lib_protocol_environment/environment_V15.ml @@ -528,6 +528,12 @@ 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 + + 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 d899e0503a564fe7a7c2220ad16897ee3a002506..cb71c6779675a624ee76a9e09f006be273dd6c09 100644 --- a/src/lib_protocol_environment/sigs/v15.ml +++ b/src/lib_protocol_environment/sigs/v15.ml @@ -9472,6 +9472,12 @@ 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 + + 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 e350f6adc6e175dbe825d0872bcb338a539c0181..5c4b2bff7c23d7fecc1d36043024183105058792 100644 --- a/src/lib_protocol_environment/sigs/v15/s.mli +++ b/src/lib_protocol_environment/sigs/v15/s.mli @@ -241,6 +241,12 @@ 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 + + val aggregate_public_key_lc_opt : + (Z.t * Public_key.t) list -> Public_key.t option end module type SPLIT_SIGNATURE = sig