From 29a33aedd331a8ff6dff7cc36b83ec0a8190566e Mon Sep 17 00:00:00 2001 From: Benjamin Canou Date: Fri, 15 Jun 2018 00:47:02 +0200 Subject: [PATCH] Client: refactor data hashing and signing commands --- src/bin_client/test/test_contracts.sh | 10 +-- .../lib_client/client_proto_programs.ml | 13 ---- .../lib_client/client_proto_programs.mli | 10 --- .../client_proto_programs_commands.ml | 73 ++++++++++--------- .../lib_protocol/src/helpers_services.ml | 20 ++--- .../lib_protocol/src/helpers_services.mli | 4 +- 6 files changed, 54 insertions(+), 76 deletions(-) diff --git a/src/bin_client/test/test_contracts.sh b/src/bin_client/test/test_contracts.sh index 69f6fc37d..bacea0ec6 100755 --- a/src/bin_client/test/test_contracts.sh +++ b/src/bin_client/test/test_contracts.sh @@ -230,8 +230,8 @@ assert_storage $contract_dir/first.tz '111' '{ 4 }' '4' # Hash input string # Test assumed to be correct -- hash is based on encoding of AST -assert_storage $contract_dir/hash_string.tz '0x00' '"abcdefg"' '0xc8e816fa5921f08d25ead933aedc189a7b0abfa97c649a8d2eb9e0f323f7909e' -assert_storage $contract_dir/hash_string.tz '0x00' '"12345"' '0x4fc401c158dad6482d96f45bb2dc10bc445b1ff127a485814d735e5c3dcb36ec' +assert_storage $contract_dir/hash_string.tz '0x00' '"abcdefg"' '0x46fdbcb4ea4eadad5615cdaa17d67f783e01e21149ce2b27de497600b4cd8f4e' +assert_storage $contract_dir/hash_string.tz '0x00' '"12345"' '0xb4c26c20de52a4eaf0d8a340db47ad8cb1e74049570859c9a9a3952b204c772f' # Test ASSERT assert_storage $contract_dir/assert.tz Unit True Unit @@ -315,11 +315,11 @@ assert_storage $contract_dir/map_caddaadr.tz \ # Did the given key sign the string? (key is bootstrap1) assert_success $client run script $contract_dir/check_signature.tz \ - on storage '(Pair "edsigtursTM9zynxFfyiLyTLuVh369H7Cd1nkH63dyc3jKBoujWeQRE9hZFRhqgTrY3BzdZenDc3D6v7gZEShpdPDMQ7YswgEL3" "hello")' \ + on storage '(Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" "hello")' \ and input '"edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav"' assert_fails $client run script $contract_dir/check_signature.tz \ - on storage '(Pair "edsigtursTM9zynxFfyiLyTLuVh369H7Cd1nkH63dyc3jKBoujWeQRE9hZFRhqgTrY3BzdZenDc3D6v7gZEShpdPDMQ7YswgEL3" "abcd")' \ + on storage '(Pair "edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" "abcd")' \ and input '"edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav"' @@ -449,7 +449,7 @@ assert_fails $client typecheck data '{ "A" ; "B" ; "B" }' against type '(set str # Test hash consistency between Michelson and the CLI hash_result=`$client hash data '(Pair 22220000000 (Pair "2017-12-13T04:49:00Z" 034))' \ - of type '(pair mutez (pair timestamp int))' | grep 0x | sed 's/.*: *//'` + of type '(pair mutez (pair timestamp int))' | grep Blake2b | sed 's/.*: *//'` assert_storage $contract_dir/hash_consistency_checker.tz '0x00' \ '(Pair 22220000000 (Pair "2017-12-13T04:49:00Z" 034))' "$hash_result" diff --git a/src/proto_alpha/lib_client/client_proto_programs.ml b/src/proto_alpha/lib_client/client_proto_programs.ml index 575493c6b..034626e5c 100644 --- a/src/proto_alpha/lib_client/client_proto_programs.ml +++ b/src/proto_alpha/lib_client/client_proto_programs.ml @@ -115,19 +115,6 @@ let trace (chain, block) program.expanded (storage.expanded, input.expanded, amount, contract) -let hash_and_sign - cctxt - ?(chain = `Main) - block - ?gas - (data : Michelson_v1_parser.parsed) - (typ : Michelson_v1_parser.parsed) - sk = - Alpha_services.Helpers.Scripts.hash_data - cctxt (chain, block) (data.expanded, typ.expanded, gas) >>=? fun (hash, gas) -> - Client_keys.sign cctxt sk (Script_expr_hash.to_bytes hash) >>=? fun signature -> - return (hash, signature, gas) - let typecheck_data cctxt ?(chain = `Main) diff --git a/src/proto_alpha/lib_client/client_proto_programs.mli b/src/proto_alpha/lib_client/client_proto_programs.mli index 9711796f4..725d5f72b 100644 --- a/src/proto_alpha/lib_client/client_proto_programs.mli +++ b/src/proto_alpha/lib_client/client_proto_programs.mli @@ -61,16 +61,6 @@ val print_trace_result : Contract.big_map_diff option) tzresult -> unit tzresult Lwt.t -val hash_and_sign : - #Proto_alpha.full -> - ?chain:Shell_services.chain -> - Shell_services.block -> - ?gas:Z.t -> - Michelson_v1_parser.parsed -> - Michelson_v1_parser.parsed -> - Client_keys.sk_uri -> - (Script_expr_hash.t * Signature.t * Gas.t) tzresult Lwt.t - val typecheck_data : #Proto_alpha.rpc_context -> ?chain:Shell_services.chain -> diff --git a/src/proto_alpha/lib_client_commands/client_proto_programs_commands.ml b/src/proto_alpha/lib_client_commands/client_proto_programs_commands.ml index d5af7e92d..99bdb4419 100644 --- a/src/proto_alpha/lib_client_commands/client_proto_programs_commands.ml +++ b/src/proto_alpha/lib_client_commands/client_proto_programs_commands.ml @@ -189,9 +189,11 @@ let commands () = cctxt#error "ill-typed data") ; command ~group - ~desc: "Ask the node to hash a data expression.\n\ + ~desc: "Ask the node to pack a data expression.\n\ The returned hash is the same as what Michelson \ - instruction `H` would have produced." + instruction `PACK` would have produced.\n\ + Also displays the result of hashing this packed data \ + with `BLAKE2B`, `SHA256` or `SHA512` instruction." (args1 custom_gas_flag) (prefixes [ "hash" ; "data" ] @@ Clic.param ~name:"data" ~desc:"the data to hash" @@ -202,12 +204,22 @@ let commands () = @@ stop) (fun custom_gas data typ cctxt -> resolve_max_gas cctxt cctxt#block custom_gas >>=? fun original_gas -> - Alpha_services.Helpers.Scripts.hash_data cctxt (`Main, cctxt#block) + Alpha_services.Helpers.Scripts.pack_data cctxt (`Main, cctxt#block) (data.expanded, typ.expanded, Some original_gas) >>= function - | Ok (hash, remaining_gas) -> - cctxt#message "Hash: %a@,Raw hash bytes: 0x%a@,Gas remaining: %a" + | Ok (bytes, remaining_gas) -> + let hash = Script_expr_hash.hash_bytes [ bytes ] in + cctxt#message + "Raw packed data: 0x%a@,\ + Hash: %a@,\ + Raw Blake2b hash: 0x%a@,\ + Raw Sha256 hash: 0x%a@,\ + Raw Sha512 hash: 0x%a@,\ + Gas remaining: %a" + MBytes.pp_hex bytes Script_expr_hash.pp hash MBytes.pp_hex (Script_expr_hash.to_bytes hash) + MBytes.pp_hex (Alpha_environment.Raw_hashes.sha256 bytes) + MBytes.pp_hex (Alpha_environment.Raw_hashes.sha512 bytes) Proto_alpha.Alpha_context.Gas.pp remaining_gas >>= fun () -> return () | Error errs -> @@ -220,40 +232,29 @@ let commands () = cctxt#error "ill-formed data") ; command ~group - ~desc: "Ask the node to hash a data expression.\n\ - Uses the same algorithm as Michelson instruction `H` to \ - produce the hash, signs it using a given secret key, and \ - displays it using the format expected by Michelson \ - instruction `CHECK_SIGNATURE`." - (args1 custom_gas_flag) - (prefixes [ "hash" ; "and" ; "sign" ; "data" ] - @@ Clic.param ~name:"data" ~desc:"the data to hash" - data_parameter - @@ prefixes [ "of" ; "type" ] - @@ Clic.param ~name:"type" ~desc:"type of the data" - data_parameter + ~desc: "Sign a raw sequence of bytes and display it using the \ + format expected by Michelson instruction \ + `CHECK_SIGNATURE`." + no_options + (prefixes [ "sign" ; "bytes" ] + @@ Clic.param ~name:"data" ~desc:"the raw data to sign" + (parameter (fun (_cctxt : full) s -> + try + if String.length s < 2 + || s.[0] <> '0' || s.[1] <> 'x' then + raise Exit + else + return (MBytes.of_hex (`Hex (String.sub s 2 (String.length s - 2)))) + with _ -> + failwith "Invalid bytes, expecting hexadecimal \ + notation (e.g. 0x1234abcd)" )) @@ prefixes [ "for" ] @@ Client_keys.Secret_key.source_param @@ stop) - (fun gas data typ sk cctxt -> - resolve_max_gas cctxt cctxt#block gas >>=? fun gas -> - Client_proto_programs.hash_and_sign cctxt cctxt#block - ~gas data typ sk >>= begin function - | Ok (hash, signature, current_gas) -> - cctxt#message "@[Hash: %a@,Raw hash bytes: 0x%a@,Signature: %a@,Remaining gas: %a@]" - Script_expr_hash.pp hash - MBytes.pp_hex (Script_expr_hash.to_bytes hash) - Signature.pp signature - Proto_alpha.Alpha_context.Gas.pp current_gas - | Error errs -> - cctxt#warning "%a" - (Michelson_v1_error_reporter.report_errors - ~details:false - ~show_source:false - ?parsed:None) - errs >>= fun () -> - cctxt#error "ill-formed data" - end >>= return) ; + (fun () bytes sk cctxt -> + Client_keys.sign cctxt sk bytes >>=? fun signature -> + cctxt#message "Signature: %a" Signature.pp signature >>= fun () -> + return ()) ; command ~group ~desc: "Ask the node to check the signature of a hashed expression." diff --git a/src/proto_alpha/lib_protocol/src/helpers_services.ml b/src/proto_alpha/lib_protocol/src/helpers_services.ml index efcb92e0f..94fb54b3f 100644 --- a/src/proto_alpha/lib_protocol/src/helpers_services.ml +++ b/src/proto_alpha/lib_protocol/src/helpers_services.ml @@ -112,20 +112,20 @@ module Scripts = struct ~output: (obj1 (req "gas" Gas.encoding)) RPC_path.(path / "typecheck_data") - let hash_data = + let pack_data = RPC_service.post_service - ~description: "Computes the hash of some data expression \ - using the same algorithm as script instruction H" + ~description: "Computes the serialized version of some data expression \ + using the same algorithm as script instruction PACK" ~input: (obj3 (req "data" Script.expr_encoding) (req "type" Script.expr_encoding) (opt "gas" z)) ~output: (obj2 - (req "hash" Script_expr_hash.encoding) + (req "packed" bytes) (req "gas" Gas.encoding)) ~query: RPC_query.empty - RPC_path.(path / "hash_data") + RPC_path.(path / "pack_data") let run_operation = RPC_service.post_service @@ -184,15 +184,15 @@ module Scripts = struct Script_ir_translator.typecheck_data ctxt (data, ty) >>=? fun ctxt -> return (Gas.level ctxt) end ; - register0 S.hash_data begin fun ctxt () (expr, typ, maybe_gas) -> + register0 S.pack_data begin fun ctxt () (expr, typ, maybe_gas) -> let open Script_ir_translator in begin match maybe_gas with | None -> return (Gas.set_unlimited ctxt) | Some gas -> Lwt.return (Gas.set_limit ctxt gas) end >>=? fun ctxt -> Lwt.return (parse_ty ~allow_big_map:false ~allow_operation:false (Micheline.root typ)) >>=? fun (Ex_ty typ) -> parse_data ctxt typ (Micheline.root expr) >>=? fun (data, ctxt) -> - Script_ir_translator.hash_data ctxt typ data >>=? fun (hash, ctxt) -> - return (hash, Gas.level ctxt) + Script_ir_translator.pack_data ctxt typ data >>=? fun (bytes, ctxt) -> + return (bytes, Gas.level ctxt) end ; register0 S.run_operation begin fun ctxt () { shell ; protocol_data = Operation_data protocol_data } -> @@ -263,8 +263,8 @@ module Scripts = struct let typecheck_data ctxt block = RPC_context.make_call0 S.typecheck_data ctxt block () - let hash_data ctxt block = - RPC_context.make_call0 S.hash_data ctxt block () + let pack_data ctxt block = + RPC_context.make_call0 S.pack_data ctxt block () let run_operation ctxt block = RPC_context.make_call0 S.run_operation ctxt block () diff --git a/src/proto_alpha/lib_protocol/src/helpers_services.mli b/src/proto_alpha/lib_protocol/src/helpers_services.mli index 3f59384a6..d1048bf80 100644 --- a/src/proto_alpha/lib_protocol/src/helpers_services.mli +++ b/src/proto_alpha/lib_protocol/src/helpers_services.mli @@ -48,9 +48,9 @@ module Scripts : sig 'a #RPC_context.simple -> 'a -> Script.expr * Script.expr * Z.t option -> Gas.t shell_tzresult Lwt.t - val hash_data: + val pack_data: 'a #RPC_context.simple -> - 'a -> Script.expr * Script.expr * Z.t option -> (Script_expr_hash.t * Gas.t) shell_tzresult Lwt.t + 'a -> Script.expr * Script.expr * Z.t option -> (MBytes.t * Gas.t) shell_tzresult Lwt.t val run_operation: 'a #RPC_context.simple ->