From 25b23ab43c07194ff3aaf6ba116a959661ebc815 Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Fri, 9 Sep 2022 15:17:25 +0200 Subject: [PATCH 1/5] Crypto: simplify signature of AGGREGATE_SIGNATURE --- src/lib_crypto/s.ml | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/src/lib_crypto/s.ml b/src/lib_crypto/s.ml index d6861cfb8bef..d7256993846e 100644 --- a/src/lib_crypto/s.ml +++ b/src/lib_crypto/s.ml @@ -438,27 +438,14 @@ module type SIGNATURE = sig end module type AGGREGATE_SIGNATURE = sig - include COMMON_SIGNATURE - - (** [sign sk message] produces the signature of [message] using [sk]. The - signature produced by this function can be aggregated to other signatures - with [agregate_signature_opt].*) - val sign : Secret_key.t -> Bytes.t -> t - - (** [check pk signature message] checks that [signature] is the signature - produced by signing [message] with the secret key of [pk]. See - [aggregate_check] if you want to check an aggregated signature.*) - val check : Public_key.t -> t -> Bytes.t -> bool - - (** [agregate_check pk_msg_list signature] checks that the list of public key - and message [pk_msg_list] produced a signature equal to [signature]. *) - val aggregate_check : (Public_key.t * bytes) list -> t -> bool - - (** [generate_key ?seed ()] creates a new pair of secret key and public key - using the seed or with a random generated one. It also returns the hash of - the public key. *) - val generate_key : - ?seed:Bytes.t -> unit -> Public_key_hash.t * Public_key.t * Secret_key.t + include SIGNATURE + + (** [agregate_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 the list of signatures [sig_list]. *) -- GitLab From d86a4d66154bc6309a4c7996147ac99517745352 Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Fri, 9 Sep 2022 15:17:47 +0200 Subject: [PATCH 2/5] Crypto: add watermark support for BLS signature/check --- src/lib_crypto/bls.ml | 36 ++++++++++++++++++++++++++++++++++-- src/lib_crypto/bls.mli | 5 ++++- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/lib_crypto/bls.ml b/src/lib_crypto/bls.ml index efe345b27e4f..c3414094b8a4 100644 --- a/src/lib_crypto/bls.ml +++ b/src/lib_crypto/bls.ml @@ -239,6 +239,8 @@ end type t = Bls12_381.Signature.MinPk.signature +type watermark = Bytes.t + let name = "Bls12_381.Signature" let title = "A Bls12_381 signature" @@ -319,9 +321,21 @@ end) let pp ppf t = Format.fprintf ppf "%s" (to_b58check t) -let sign = Bls12_381.Signature.MinPk.Aug.sign +let zero = + Bls12_381.Signature.MinPk.signature_of_bytes_exn + @@ Bytes.of_string + "\192\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + +let sign ?watermark sk msg = + let msg = + match watermark with None -> msg | Some prefix -> Bytes.cat prefix msg + in + Bls12_381.Signature.MinPk.Aug.sign sk msg -let check pk signature msg = +let check ?watermark pk signature msg = + let msg = + match watermark with None -> msg | Some prefix -> Bytes.cat prefix msg + in Bls12_381.Signature.MinPk.Aug.verify pk msg signature (* [seed] must be at least of 32 bytes or [Bls12_381.Signature.generate_sk] will @@ -340,7 +354,25 @@ let generate_key ?seed () = let pkh = Public_key.hash pk in (pkh, pk, sk) +let deterministic_nonce sk msg = + let key = Secret_key.to_bytes sk in + Hacl.Hash.SHA256.HMAC.digest ~key ~msg + +let deterministic_nonce_hash sk msg = + Blake2B.to_bytes (Blake2B.hash_bytes [deterministic_nonce sk msg]) + let aggregate_check pk_msg_list signature = + let pk_msg_list = + List.map + (fun (pk, watermark, msg) -> + let msg = + match watermark with + | None -> msg + | Some prefix -> Bytes.cat prefix msg + in + (pk, msg)) + pk_msg_list + in Bls12_381.Signature.MinPk.Aug.aggregate_verify pk_msg_list signature let aggregate_signature_opt = Bls12_381.Signature.MinPk.aggregate_signature_opt diff --git a/src/lib_crypto/bls.mli b/src/lib_crypto/bls.mli index 3be4352c4b40..42bce61a3fa9 100644 --- a/src/lib_crypto/bls.mli +++ b/src/lib_crypto/bls.mli @@ -1,7 +1,7 @@ (*****************************************************************************) (* *) (* Open Source License *) -(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. *) +(* Copyright (c) 2021 Nomadic Labs *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -23,10 +23,13 @@ (* *) (*****************************************************************************) +(** Tezos - BLS12-381 cryptography *) + include S.AGGREGATE_SIGNATURE with type Public_key.t = Bls12_381.Signature.MinPk.pk and type Secret_key.t = Bls12_381.Signature.sk and type t = Bls12_381.Signature.MinPk.signature + and type watermark = Bytes.t include S.RAW_DATA with type t := t -- GitLab From fe882c004fc524641b6764110ee223b52575e023 Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Fri, 9 Sep 2022 15:18:00 +0200 Subject: [PATCH 3/5] Crypto: add watermark support for aggregate signatures Co-author: Alain Mebsout Co-author: Sylvain R --- src/lib_crypto/aggregate_signature.ml | 24 +++++++++++++++++++----- src/lib_crypto/aggregate_signature.mli | 1 + 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/lib_crypto/aggregate_signature.ml b/src/lib_crypto/aggregate_signature.ml index 3683bd79474c..080560895fba 100644 --- a/src/lib_crypto/aggregate_signature.ml +++ b/src/lib_crypto/aggregate_signature.ml @@ -364,6 +364,8 @@ type signature = Bls12_381 of Bls.t | Unknown of Bytes.t type t = signature +type watermark = Bytes.t + let name = "Aggregate signature" let title = "A Bls12_381 signature" @@ -456,16 +458,19 @@ end) let pp ppf t = Format.fprintf ppf "%s" (to_b58check t) -let sign (Secret_key.Bls12_381 sk) bytes = Bls12_381 (Bls.sign sk bytes) +let zero = Bls12_381 Bls.zero + +let sign ?watermark (Secret_key.Bls12_381 sk) bytes = + Bls12_381 (Bls.sign ?watermark sk bytes) -let check pk signature message = +let check ?watermark pk signature message = match (pk, signature) with | Public_key.Bls12_381 pk, Unknown signature -> Bls.of_bytes_opt signature - |> Option.map (fun signature -> Bls.check pk signature message) + |> Option.map (fun signature -> Bls.check ?watermark pk signature message) |> Option.value ~default:false | Public_key.Bls12_381 pk, Bls12_381 signature -> - Bls.check pk signature message + Bls.check ?watermark pk signature message let generate_key ?seed () = let pkh, pk, sk = Bls.generate_key ?seed () in @@ -473,9 +478,18 @@ let generate_key ?seed () = Public_key.Bls12_381 pk, Secret_key.Bls12_381 sk ) +let deterministic_nonce (Secret_key.Bls12_381 sk) msg = + Bls.deterministic_nonce sk msg + +let deterministic_nonce_hash (Secret_key.Bls12_381 sk) msg = + Bls.deterministic_nonce_hash sk msg + let aggregate_check pks signature = let pks = - List.map (fun (Public_key.Bls12_381 pk, bytes) -> (pk, bytes)) pks + List.map + (fun (Public_key.Bls12_381 pk, watermark, bytes) -> + (pk, watermark, bytes)) + pks in match signature with | Bls12_381 signature -> Bls.aggregate_check pks signature diff --git a/src/lib_crypto/aggregate_signature.mli b/src/lib_crypto/aggregate_signature.mli index 68fb01dd231c..0196e5035c64 100644 --- a/src/lib_crypto/aggregate_signature.mli +++ b/src/lib_crypto/aggregate_signature.mli @@ -36,5 +36,6 @@ include and type Public_key.t = public_key and type Secret_key.t = secret_key and type t = signature + and type watermark = Bytes.t include S.RAW_DATA with type t := t -- GitLab From e308174a5ab70e2ac9579e4b2e31fe272956bae6 Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Fri, 9 Sep 2022 15:20:25 +0200 Subject: [PATCH 4/5] Test: fix signature tests --- src/lib_crypto/test/test_prop_signature.ml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib_crypto/test/test_prop_signature.ml b/src/lib_crypto/test/test_prop_signature.ml index 0c1d870fdea1..3a4e42ee398e 100644 --- a/src/lib_crypto/test/test_prop_signature.ml +++ b/src/lib_crypto/test/test_prop_signature.ml @@ -76,7 +76,10 @@ struct let is_valid_aggregated_sign = X.aggregate_signature_opt [signed1; signed2; signed3] |> function | None -> false - | Some s -> X.aggregate_check [(pk1, msg1); (pk2, msg2); (pk3, msg3)] s + | Some s -> + X.aggregate_check + [(pk1, None, msg1); (pk2, None, msg2); (pk3, None, msg3)] + s in X.check pk1 signed1 msg1 && X.check pk2 signed2 msg2 && X.check pk3 signed3 msg3 && is_valid_aggregated_sign -- GitLab From 740bd74d46e8527976794476006049491d8c90e0 Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Fri, 9 Sep 2022 15:54:42 +0200 Subject: [PATCH 5/5] Test: test signatures with watermarks --- src/lib_crypto/test/test_prop_signature.ml | 91 ++++++++++++++++------ 1 file changed, 68 insertions(+), 23 deletions(-) diff --git a/src/lib_crypto/test/test_prop_signature.ml b/src/lib_crypto/test/test_prop_signature.ml index 3a4e42ee398e..9531322c8a92 100644 --- a/src/lib_crypto/test/test_prop_signature.ml +++ b/src/lib_crypto/test/test_prop_signature.ml @@ -34,55 +34,89 @@ open Lib_test.Qcheck2_helpers open QCheck2 +module type SIGNATURE = sig + include S.SIGNATURE + + val watermark_of_bytes : bytes -> watermark +end + +let gen_watermark = + let open Gen in + Gen.char >|= Bytes.make 1 + module Signature_Properties (Desc : sig val name : string end) -(X : S.SIGNATURE) = +(X : SIGNATURE) = struct (** Tests that a signature of [s] by a generated key and [X.sign] is accepted by [X.check] with the same key. *) - let test_prop_sign_check (s : string) = + let test_prop_sign_check (s, watermark) = let _, pk, sk = X.generate_key () in let data = Bytes.of_string s in - let signed = X.sign sk data in - X.check pk signed data + let watermark = Option.map X.watermark_of_bytes watermark in + let signed = X.sign ?watermark sk data in + X.check ?watermark pk signed data + + let gen = + let open Gen in + let+ msg = string and+ wm1 = gen_watermark |> option in + (msg, wm1) let test_prop_sign_check = Test.make ~name:(Desc.name ^ "_sign_check") - ~print:Print.string - Gen.string + ~print:Print.(pair string (option Bytes.unsafe_to_string)) + gen test_prop_sign_check let tests = [test_prop_sign_check] end +module type AGGREGATE_SIGNATURE = sig + include S.AGGREGATE_SIGNATURE + + val watermark_of_bytes : bytes -> watermark +end + module Aggregate_Signature_Properties (Desc : sig val name : string end) -(X : S.AGGREGATE_SIGNATURE) = +(X : AGGREGATE_SIGNATURE) = struct (** Tests that signatures of [s] obtained using [X.sign] are accepted by [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 ((seed1, msg1), (seed2, msg2), (seed3, msg3)) = + let test_prop_sign_check + ( (seed1, msg1, watermark1), + (seed2, msg2, watermark2), + (seed3, msg3, watermark3) ) = 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 signed1 = X.sign sk1 msg1 in - let signed2 = X.sign sk2 msg2 in - let signed3 = X.sign sk3 msg3 in + let watermark1 = Option.map X.watermark_of_bytes watermark1 in + let watermark2 = Option.map X.watermark_of_bytes watermark2 in + let watermark3 = Option.map X.watermark_of_bytes watermark3 in + let signed1 = X.sign ?watermark:watermark1 sk1 msg1 in + let signed2 = X.sign ?watermark:watermark2 sk2 msg2 in + let signed3 = X.sign ?watermark:watermark3 sk3 msg3 in let is_valid_aggregated_sign = X.aggregate_signature_opt [signed1; signed2; signed3] |> function | None -> false | Some s -> X.aggregate_check - [(pk1, None, msg1); (pk2, None, msg2); (pk3, None, msg3)] + [ + (pk1, watermark1, msg1); + (pk2, watermark2, msg2); + (pk3, watermark3, msg3); + ] s in - X.check pk1 signed1 msg1 && X.check pk2 signed2 msg2 - && X.check pk3 signed3 msg3 && is_valid_aggregated_sign + X.check ?watermark:watermark1 pk1 signed1 msg1 + && X.check ?watermark:watermark2 pk2 signed2 msg2 + && X.check ?watermark:watermark3 pk3 signed3 msg3 + && is_valid_aggregated_sign let test_prop_sign_check = let gen = @@ -92,17 +126,22 @@ struct and+ seed3 = string_size (pure 32) >|= Bytes.of_string and+ msg1 = string >|= Bytes.of_string and+ msg2 = string >|= Bytes.of_string - and+ msg3 = string >|= Bytes.of_string in - ((seed1, msg1), (seed2, msg2), (seed3, msg3)) + and+ msg3 = string >|= Bytes.of_string + and+ wm1 = gen_watermark |> option + and+ wm2 = gen_watermark |> option + and+ wm3 = gen_watermark |> option in + ((seed1, msg1, wm1), (seed2, msg2, wm2), (seed3, msg3, wm3)) + in + let print_param = + Print.( + triple + Bytes.unsafe_to_string + Bytes.unsafe_to_string + (option Bytes.unsafe_to_string)) in Test.make ~name:("Aggregate_signature_" ^ Desc.name ^ "_sign_check") - ~print: - Print.( - triple - (pair Bytes.unsafe_to_string Bytes.unsafe_to_string) - (pair Bytes.unsafe_to_string Bytes.unsafe_to_string) - (pair Bytes.unsafe_to_string Bytes.unsafe_to_string)) + ~print:(Print.triple print_param print_param print_param) gen test_prop_sign_check @@ -118,13 +157,19 @@ let () = (struct let name = "Bls12_381" end) - (Bls) + (struct + include Bls + + let watermark_of_bytes b = b + end) in let f (algo, name) = let module X = struct include Signature let generate_key ?seed () = generate_key ~algo ?seed () + + let watermark_of_bytes b = Custom b end in let module XProps = Signature_Properties -- GitLab