From 4309f9bac5ddc449aacb46724d3c53ba4c7b55d8 Mon Sep 17 00:00:00 2001 From: Adam Allombert-Goget Date: Mon, 3 Feb 2025 13:50:19 +0100 Subject: [PATCH 1/6] proto: check signature with bls_mode encoding under feature flag --- src/proto_alpha/lib_protocol/alpha_context.ml | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/src/proto_alpha/lib_protocol/alpha_context.ml b/src/proto_alpha/lib_protocol/alpha_context.ml index 40940a956160..3ea45f381fc8 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.ml +++ b/src/proto_alpha/lib_protocol/alpha_context.ml @@ -189,6 +189,21 @@ module Entrypoint = Entrypoint_repr module Manager_counter = Manager_counter_repr include Operation_repr +module Constants = struct + include Constants_repr + include Constants_storage + + module Parametric = struct + include Constants_parametric_repr + + module Internal_for_tests = struct + include Internal_for_tests + + let update_sc_rollup_parameter = update_sc_rollup_parameter + end + end +end + module Operation = struct type 'kind t = 'kind operation = { shell : Operation.shell_header; @@ -203,7 +218,17 @@ module Operation = struct include Operation_repr - let check_signature _ctxt = check_signature unsigned_encoding + let check_signature (type kind) ctxt (key : Signature.Public_key.t) chain_id + (op : kind operation) = + let encoding = + if Constants.aggregate_attestation ctxt then + (* attestations signed by BLS keys uses a dedicated serialization encoding *) + match (op.protocol_data.contents, key) with + | Single (Attestation _), Bls _ -> bls_mode_unsigned_encoding + | _ -> unsigned_encoding + else unsigned_encoding + in + check_signature encoding key chain_id op module Internal_for_tests = struct let serialize_unsigned_operation _ctxt branch contents = @@ -268,21 +293,6 @@ type public_key_hash = Signature.Public_key_hash.t type signature = Signature.t -module Constants = struct - include Constants_repr - include Constants_storage - - module Parametric = struct - include Constants_parametric_repr - - module Internal_for_tests = struct - include Internal_for_tests - - let update_sc_rollup_parameter = update_sc_rollup_parameter - end - end -end - module Voting_period = struct include Voting_period_repr include Voting_period_storage -- GitLab From 3102d1b9b630ef2edf7ff0babe3067dfb882ddb0 Mon Sep 17 00:00:00 2001 From: Adam Allombert-Goget Date: Wed, 5 Feb 2025 12:17:00 +0100 Subject: [PATCH 2/6] baker: sign consensus ops with bls_mode encoding under feature flag --- src/proto_alpha/lib_delegate/baking_actions.ml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/proto_alpha/lib_delegate/baking_actions.ml b/src/proto_alpha/lib_delegate/baking_actions.ml index 2d2b9be42351..cfa3b1ab5135 100644 --- a/src/proto_alpha/lib_delegate/baking_actions.ml +++ b/src/proto_alpha/lib_delegate/baking_actions.ml @@ -678,10 +678,17 @@ let forge_and_sign_consensus_vote global_state ~branch unsigned_consensus_vote : | Attestation -> `Attestation in let unsigned_operation = (shell, Contents_list contents) in + let bls_mode = + match delegate.consensus_key.public_key with + | Bls _ -> global_state.constants.parametric.aggregate_attestation + | _ -> false + in + let encoding = + if bls_mode then Operation.bls_mode_unsigned_encoding + else Operation.unsigned_encoding + in let unsigned_operation_bytes = - Data_encoding.Binary.to_bytes_exn - Operation.unsigned_encoding - unsigned_operation + Data_encoding.Binary.to_bytes_exn encoding unsigned_operation in let sk_uri = delegate.consensus_key.secret_key_uri in let* signature = -- GitLab From 7f60f4c0df23759c9d73286d560fa671012bcf90 Mon Sep 17 00:00:00 2001 From: Adam Allombert-Goget Date: Fri, 7 Feb 2025 17:08:41 +0100 Subject: [PATCH 3/6] tezt: add helper for forge/bls_consensus_operations RPC --- tezt/lib_tezos/RPC.ml | 16 ++++++++++++++++ tezt/lib_tezos/RPC.mli | 8 ++++++++ 2 files changed, 24 insertions(+) diff --git a/tezt/lib_tezos/RPC.ml b/tezt/lib_tezos/RPC.ml index 53b260c73bd8..a23206215f4f 100644 --- a/tezt/lib_tezos/RPC.ml +++ b/tezt/lib_tezos/RPC.ml @@ -591,6 +591,22 @@ let post_chain_block_helpers_forge_operations ?(chain = "main") ["chains"; chain; "blocks"; block; "helpers"; "forge"; "operations"] Fun.id +let post_chain_block_helpers_forge_bls_consensus_operations ?(chain = "main") + ?(block = "head") ~data () = + make + ~data + POST + [ + "chains"; + chain; + "blocks"; + block; + "helpers"; + "forge"; + "bls_consensus_operations"; + ] + Fun.id + let post_chain_block_helpers_forge_block_header ?(chain = "main") ?(block = "head") ~data () = make diff --git a/tezt/lib_tezos/RPC.mli b/tezt/lib_tezos/RPC.mli index 7fa3bba5be4c..d9742b3b2ce2 100644 --- a/tezt/lib_tezos/RPC.mli +++ b/tezt/lib_tezos/RPC.mli @@ -571,6 +571,14 @@ val post_chain_block_helpers_preapply_operations : val post_chain_block_helpers_forge_operations : ?chain:string -> ?block:string -> data:data -> unit -> JSON.t t +(** RPC: [POST /chains//blocks//helpers/forge/consensus_operations] + + [chain] defaults to ["main"]. + [block] defaults to ["head"]. +*) +val post_chain_block_helpers_forge_bls_consensus_operations : + ?chain:string -> ?block:string -> data:data -> unit -> JSON.t t + (** RPC: [POST /chains//blocks//helpers/forge_block_header] [chain] defaults to ["main"]. -- GitLab From 39d353c7fe7c2456dbcd2d9c362f2c9a1b042e26 Mon Sep 17 00:00:00 2001 From: Adam Allombert-Goget Date: Sat, 8 Feb 2025 12:19:13 +0100 Subject: [PATCH 4/6] tezt: support bls_mode encoding for consensus ops signed by bls keys --- tezt/lib_tezos/operation_core.ml | 71 +++++++++++++++++++++---------- tezt/lib_tezos/operation_core.mli | 1 + 2 files changed, 50 insertions(+), 22 deletions(-) diff --git a/tezt/lib_tezos/operation_core.ml b/tezt/lib_tezos/operation_core.ml index 95172391ae52..798f81fe7535 100644 --- a/tezt/lib_tezos/operation_core.ml +++ b/tezt/lib_tezos/operation_core.ml @@ -91,35 +91,61 @@ let hex ?protocol ?signature t client = let (`Hex signature) = Tezos_crypto.Signature.to_hex signature in return (`Hex (raw ^ signature)) +let bls_mode_raw t client : Hex.t Lwt.t = + let* json = + Client.RPC.call client + @@ RPC.post_chain_block_helpers_forge_bls_consensus_operations + ~data:(Data (json t)) + () + in + let sign_bytes = JSON.(json |-> "sign" |> as_string) in + let inject_bytes = JSON.(json |-> "inject" |> as_string) in + t.raw <- Some (`Hex inject_bytes) ; + return (`Hex sign_bytes) + let sign ?protocol ({kind; signer; _} as t) client = + let is_tz4 = String.starts_with ~prefix:"tz4" in match signer with | None -> return Tezos_crypto.Signature.zero - | Some signer -> - let watermark = - match kind with - | Consensus {kind; chain_id} -> - let chain_id = - Tezos_crypto.Hashed.Chain_id.to_string - (Tezos_crypto.Hashed.Chain_id.of_b58check_exn chain_id) - in - let prefix = - match kind with - | Preattestation -> "\x12" - | Attestation _ -> "\x13" - in + | Some signer -> ( + match kind with + | Consensus {kind; chain_id} -> + let chain_id = + Tezos_crypto.Hashed.Chain_id.to_string + (Tezos_crypto.Hashed.Chain_id.of_b58check_exn chain_id) + in + let prefix = + match kind with Preattestation -> "\x12" | Attestation _ -> "\x13" + in + let watermark = Tezos_crypto.Signature.Custom (Bytes.cat (Bytes.of_string prefix) (Bytes.of_string chain_id)) - | Anonymous | Voting | Manager -> - Tezos_crypto.Signature.Generic_operation - in - let* hex = hex ?protocol t client in - let bytes = Hex.to_bytes hex in - return (Account.sign_bytes ~watermark ~signer bytes) + in + let* hex = + match protocol with + | Some p + when Protocol.number p >= 023 && is_tz4 signer.public_key_hash -> + let* constants = + Client.RPC.call client + @@ RPC.get_chain_block_context_constants () + in + if JSON.(constants |-> "aggregate_attestation" |> as_bool) then + bls_mode_raw t client + else hex ?protocol t client + | _ -> hex ?protocol t client + in + let bytes = Hex.to_bytes hex in + return (Account.sign_bytes ~watermark ~signer bytes) + | Anonymous | Voting | Manager -> + let watermark = Tezos_crypto.Signature.Generic_operation in + let* hex = hex ?protocol t client in + let bytes = Hex.to_bytes hex in + return (Account.sign_bytes ~watermark ~signer bytes)) let signed_hex ?protocol ?signature t client = let* signature = match signature with - | None -> sign t client + | None -> sign ?protocol t client | Some signature -> return signature in hex ?protocol ~signature t client @@ -354,9 +380,10 @@ module Consensus = struct in return (make ~branch ~signer ~kind:(Consensus {kind; chain_id}) json) - let inject ?request ?force ?branch ?chain_id ?error ~signer consensus client = + let inject ?request ?force ?branch ?chain_id ?error ~protocol ~signer + consensus client = let* op = operation ?branch ?chain_id ~signer consensus client in - inject ?request ?force ?error op client + inject ?request ?force ?error ~protocol op client let get_slots ~level client = Client.RPC.call client @@ RPC.get_chain_block_helper_validators ~level () diff --git a/tezt/lib_tezos/operation_core.mli b/tezt/lib_tezos/operation_core.mli index 9938c6be508e..0b9ce4de7df0 100644 --- a/tezt/lib_tezos/operation_core.mli +++ b/tezt/lib_tezos/operation_core.mli @@ -300,6 +300,7 @@ module Consensus : sig ?branch:string -> ?chain_id:string -> ?error:rex -> + protocol:Protocol.t -> signer:Account.key -> t -> Client.t -> -- GitLab From b359e42dc2398703450f8fce0b11965a794b9a86 Mon Sep 17 00:00:00 2001 From: Adam Allombert-Goget Date: Sat, 8 Feb 2025 12:20:52 +0100 Subject: [PATCH 5/6] tezt: adapt tests to provide a protocol when signing consensus ops --- tezt/tests/double_consensus.ml | 20 ++++++++++++++++++-- tezt/tests/prevalidator.ml | 6 ++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/tezt/tests/double_consensus.ml b/tezt/tests/double_consensus.ml index a95b6fec9fdb..37f715a0fa1f 100644 --- a/tezt/tests/double_consensus.ml +++ b/tezt/tests/double_consensus.ml @@ -120,7 +120,12 @@ let double_consensus_wrong_slot in let waiter = consensus_waiter accuser in let* _ = - Operation.Consensus.inject ~branch ~signer:Constant.bootstrap1 op client + Operation.Consensus.inject + ~protocol + ~branch + ~signer:Constant.bootstrap1 + op + client in let* () = waiter in Log.info @@ -134,7 +139,12 @@ let double_consensus_wrong_slot double_consensus_already_denounced_waiter accuser oph in let* _ = - Operation.Consensus.inject ~branch ~signer:Constant.bootstrap1 op client + Operation.Consensus.inject + ~protocol + ~branch + ~signer:Constant.bootstrap1 + op + client in let* () = waiter_already_denounced in unit @@ -185,6 +195,7 @@ let double_consensus_wrong_block_payload_hash let* _ = Operation.Consensus.inject ~force:true + ~protocol ~branch ~signer:Constant.bootstrap1 op @@ -208,6 +219,7 @@ let double_consensus_wrong_block_payload_hash let* _ = Operation.Consensus.inject ~force:true + ~protocol ~branch ~signer:Constant.bootstrap1 op @@ -264,6 +276,7 @@ let double_consensus_wrong_branch let* _ = Operation.Consensus.inject ~force:true + ~protocol ~branch ~signer:Constant.bootstrap1 op @@ -284,6 +297,7 @@ let double_consensus_wrong_branch let* _ = Operation.Consensus.inject ~force:true + ~protocol ~branch ~signer:Constant.bootstrap1 op @@ -361,6 +375,7 @@ let operation_too_old = let* _ = Operation.Consensus.inject ~force:true + ~protocol ~branch ~signer:Constant.bootstrap1 op @@ -438,6 +453,7 @@ let operation_too_far_in_future = let* _ = Operation.Consensus.inject ~force:true + ~protocol ~branch ~signer:Constant.bootstrap1 op diff --git a/tezt/tests/prevalidator.ml b/tezt/tests/prevalidator.ml index 86ef77d4f1de..d86fde531f89 100644 --- a/tezt/tests/prevalidator.ml +++ b/tezt/tests/prevalidator.ml @@ -1917,6 +1917,7 @@ module Revamped = struct ~round:0 ~block_payload_hash ()) + ~protocol ~signer:delegate client in @@ -2429,6 +2430,7 @@ module Revamped = struct ~round:0 ~block_payload_hash ()) + ~protocol ~signer:account client in @@ -2541,6 +2543,7 @@ module Revamped = struct ~round:0 ~block_payload_hash ()) + ~protocol ~signer:account client in @@ -2672,6 +2675,7 @@ module Revamped = struct ~round:0 ~block_payload_hash ()) + ~protocol ~signer client in @@ -2916,6 +2920,7 @@ module Revamped = struct let* _ = Operation.Consensus.inject ~force:true + ~protocol ~branch:branch_future1 ~signer:Constant.bootstrap1 op_future1 @@ -2924,6 +2929,7 @@ module Revamped = struct let* _ = Operation.Consensus.inject ~force:true + ~protocol ~branch:branch_future2 ~signer:Constant.bootstrap1 op_future2 -- GitLab From a5965960cb40e9cdfcb7b8e86715805d40280a3f Mon Sep 17 00:00:00 2001 From: Adam Allombert-Goget Date: Sun, 9 Feb 2025 00:17:20 +0100 Subject: [PATCH 6/6] tezt: fix encoding retrieval in operation serialization helper --- tezt/lib_tezos/operation_core.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tezt/lib_tezos/operation_core.ml b/tezt/lib_tezos/operation_core.ml index 798f81fe7535..b963710ae320 100644 --- a/tezt/lib_tezos/operation_core.ml +++ b/tezt/lib_tezos/operation_core.ml @@ -68,7 +68,7 @@ let raw ?protocol t client = t.raw <- Some (`Hex raw) ; return (`Hex raw) | Some p -> ( - let name = Protocol.daemon_name p ^ ".operation.unsigned" in + let name = Protocol.encoding_prefix p ^ ".operation.unsigned" in match Data_encoding.Registration.find name with | None -> Test.fail "%s encoding was not found" name | Some registered -> ( -- GitLab