From fc53f3b233af067c83dac54295b2b8c7bcb295f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Henry?= Date: Sun, 19 Feb 2017 18:22:32 +0100 Subject: [PATCH] Switch to Base58. Base48 was fun but... hell yeah... let's stay standard. Public encoding of hash: ``` Block: "B..." (len: 51) Operation: "o..." (len: 51) Protocol: "P..." (len: 51) Ed25519: "tz1.." (len: 36) Contract: "TZ1.." (len: 36) NetworkdId: "id.." (len: 30) ``` Other internal prefixes (in the RPC): ``` Hash of Michelson's expression: "expr..." (len: 54) Ed25519 public key: "edpk..." (len: 54) Ed25519 secret key: "edsk..." (len: 98) Ed25519 signature: "edsig.." (len: 99) Hash of a random seed nonce: "nce...." (len: 53) Random seed: "rng...." (len: 53) ``` --- .gitignore | 1 + src/.merlin | 1 + src/Makefile | 7 +- src/attacker/attacker_minimal.ml | 4 +- src/client/client_helpers.ml | 4 +- src/client/client_keys.ml | 4 +- src/client/client_protocols.ml | 2 +- .../bootstrap/client_proto_context.ml | 2 +- .../bootstrap/client_proto_contracts.ml | 12 +- .../embedded/bootstrap/client_proto_main.ml | 4 +- .../webclient_proto_service_directory.ml | 2 +- src/client/embedded/demo/client_proto_main.ml | 4 +- src/compiler/tezos_compiler.ml | 6 +- src/minutils/utils.ml | 15 + src/minutils/utils.mli | 3 + src/node/db/context.ml | 12 +- src/node/db/store.ml | 8 +- src/node/main/node_run_command.ml | 8 +- src/node/shell/node.ml | 10 +- src/node/shell/node_rpc_services.ml | 16 +- src/node/updater/environment.ml | 67 ++-- src/node/updater/environment_gen.ml | 3 +- src/node/updater/protocol.mli | 3 +- src/node/updater/updater.ml | 11 +- src/node/updater/updater.mli | 3 +- src/proto/bootstrap/TEZOS_PROTOCOL | 2 +- src/proto/bootstrap/contract_repr.ml | 20 +- src/proto/bootstrap/contract_repr.mli | 4 +- src/proto/bootstrap/contract_storage.ml | 4 +- src/proto/bootstrap/script_ir_translator.ml | 8 +- src/proto/bootstrap/script_repr.ml | 2 +- src/proto/bootstrap/services.ml | 4 +- src/proto/bootstrap/storage_functors.ml | 2 +- src/proto/bootstrap/tezos_context.mli | 4 +- src/proto/bootstrap/tezos_hash.ml | 39 ++- src/proto/demo/TEZOS_PROTOCOL | 2 +- src/proto/environment/base48.mli | 20 -- src/proto/environment/base58.mli | 19 ++ src/proto/environment/context.mli | 5 +- src/proto/environment/hash.mli | 17 +- src/utils/base48.ml | 238 ------------- src/utils/base58.ml | 312 ++++++++++++++++++ src/utils/{base48.mli => base58.mli} | 88 +++-- src/utils/crypto_box.ml | 7 +- src/utils/hash.ml | 59 ++-- src/utils/hash.mli | 17 +- test/Makefile | 6 + test/generate_hash.ml | 63 ++++ test/lib/assert.ml | 2 +- test/test_context.ml | 8 +- test/test_state.ml | 8 +- test/test_store.ml | 21 +- 52 files changed, 685 insertions(+), 508 deletions(-) delete mode 100644 src/proto/environment/base48.mli create mode 100644 src/proto/environment/base58.mli delete mode 100644 src/utils/base48.ml create mode 100644 src/utils/base58.ml rename src/utils/{base48.mli => base58.mli} (59%) create mode 100644 test/generate_hash.ml diff --git a/.gitignore b/.gitignore index c1f626690..352b3fe16 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,7 @@ /test/test-p2p-io-scheduler /test/test-p2p-connection /test/test-p2p-connection-pool +/test/generate_hash /test/LOG *~ diff --git a/src/.merlin b/src/.merlin index adbd081bd..01927e0d4 100644 --- a/src/.merlin +++ b/src/.merlin @@ -38,6 +38,7 @@ PKG ipv6-multicast PKG irmin PKG lwt PKG mtime.os +PKG nocrypto PKG ocplib-endian PKG ocplib-json-typed PKG ocplib-ocamlres diff --git a/src/Makefile b/src/Makefile index 2deb4c332..3e21d54dc 100644 --- a/src/Makefile +++ b/src/Makefile @@ -36,7 +36,7 @@ $(addprefix proto/environment/, \ error_monad.mli \ logging.mli \ time.mli \ - base48.mli \ + base58.mli \ hash.mli \ ed25519.mli \ persist.mli \ @@ -150,7 +150,7 @@ minutils.cma: ${MINUTILS_LIB_IMPLS:.ml=.cmo} ############################################################################ UTILS_LIB_INTFS := \ - utils/base48.mli \ + utils/base58.mli \ utils/cli_entries.mli \ utils/data_encoding_ezjsonm.mli \ utils/crypto_box.mli \ @@ -166,7 +166,7 @@ UTILS_LIB_INTFS := \ utils/ring.mli \ UTILS_LIB_IMPLS := \ - utils/base48.ml \ + utils/base58.ml \ utils/cli_entries.ml \ utils/error_monad_sig.ml \ utils/error_monad.ml \ @@ -189,6 +189,7 @@ UTILS_PACKAGES := \ ezjsonm \ ipaddr.unix \ mtime.os \ + nocrypto \ sodium \ zarith \ $(COVERAGEPKG) \ diff --git a/src/attacker/attacker_minimal.ml b/src/attacker/attacker_minimal.ml index abafdf4e1..8fad1e4d9 100644 --- a/src/attacker/attacker_minimal.ml +++ b/src/attacker/attacker_minimal.ml @@ -14,8 +14,8 @@ module Proto = Client_embedded_proto_bootstrap module Ed25519 = Proto.Local_environment.Environment.Ed25519 (* the genesis block and network *) -let genesis_block_hashed = Block_hash.of_b48check - "grHGHkVfgJb5gPaRd5AtQsa65g9GyLcXgQsHbSnQ5SD5DEp2ctqck" +let genesis_block_hashed = Block_hash.of_b58check + "BLockGenesisGenesisGenesisGenesisGenesisGeneskvg68z" let network = Store.Net genesis_block_hashed (* the bootstrap accounts and actions like signing to do with them *) diff --git a/src/client/client_helpers.ml b/src/client/client_helpers.ml index 20b4db683..333ba361b 100644 --- a/src/client/client_helpers.ml +++ b/src/client/client_helpers.ml @@ -18,14 +18,14 @@ let unique_arg = let commands () = Cli_entries.[ command ~desc: "Lookup for the possible completion of a \ - given prefix of Base48Check-encoded hash. This actually \ + given prefix of Base58Check-encoded hash. This actually \ works only for blocks, operations, public key and contract \ identifiers." ~args: [unique_arg] (prefixes [ "complete" ] @@ string ~name: "prefix" - ~desc: "the prefix of the Base48Check-encoded hash to be completed" @@ + ~desc: "the prefix of the Base58Check-encoded hash to be completed" @@ stop) (fun prefix cctxt -> Client_node_rpcs.complete cctxt ~block:(block ()) prefix >>= fun completions -> diff --git a/src/client/client_keys.ml b/src/client/client_keys.ml index dcd013a9a..fa118451c 100644 --- a/src/client/client_keys.ml +++ b/src/client/client_keys.ml @@ -12,8 +12,8 @@ module Ed25519 = Environment.Ed25519 module Public_key_hash = Client_aliases.Alias (struct type t = Ed25519.Public_key_hash.t let encoding = Ed25519.Public_key_hash.encoding - let of_source _ s = Lwt.return (Ed25519.Public_key_hash.of_b48check s) - let to_source _ p = Lwt.return (Ed25519.Public_key_hash.to_b48check p) + let of_source _ s = Lwt.return (Ed25519.Public_key_hash.of_b58check s) + let to_source _ p = Lwt.return (Ed25519.Public_key_hash.to_b58check p) let name = "public key hash" end) diff --git a/src/client/client_protocols.ml b/src/client/client_protocols.ml index 574b48670..23ffd5ccb 100644 --- a/src/client/client_protocols.ml +++ b/src/client/client_protocols.ml @@ -19,7 +19,7 @@ let commands () = else Lwt.fail_with (dn ^ " is not a directory") in let check_hash _ ph = - Lwt.wrap1 Protocol_hash.of_b48check ph in + Lwt.wrap1 Protocol_hash.of_b58check ph in [ command ~group ~desc: "list known protocols" (prefixes [ "list" ; "protocols" ] stop) diff --git a/src/client/embedded/bootstrap/client_proto_context.ml b/src/client/embedded/bootstrap/client_proto_context.ml index 0456526f1..93ff1b0f5 100644 --- a/src/client/embedded/bootstrap/client_proto_context.ml +++ b/src/client/embedded/bootstrap/client_proto_context.ml @@ -54,7 +54,7 @@ let list_contracts cctxt block = let kind = match Contract.is_default h with | Some _ -> " (default)" | None -> "" in - cctxt.message "%s%s%s" (Contract.to_b48check h) kind nm >>= fun () -> + cctxt.message "%s%s%s" (Contract.to_b58check h) kind nm >>= fun () -> return ()) contracts diff --git a/src/client/embedded/bootstrap/client_proto_contracts.ml b/src/client/embedded/bootstrap/client_proto_contracts.ml index cb2bf27e2..67237c759 100644 --- a/src/client/embedded/bootstrap/client_proto_contracts.ml +++ b/src/client/embedded/bootstrap/client_proto_contracts.ml @@ -13,11 +13,11 @@ module RawContractAlias = Client_aliases.Alias (struct type t = Contract.t let encoding = Contract.encoding let of_source _ s = - match Contract.of_b48check s with + match Contract.of_b58check s with | Error _ -> Lwt.fail (Failure "bad contract notation") | Ok s -> Lwt.return s let to_source _ s = - Lwt.return (Contract.to_b48check s) + Lwt.return (Contract.to_b58check s) let name = "contract" end) @@ -75,14 +75,14 @@ module ContractAlias = struct Lwt.catch (fun () -> find cctxt s) (fun _ -> - match Contract.of_b48check s with + match Contract.of_b58check s with | Error _ -> Lwt.fail (Failure "bad contract notation") | Ok v -> Lwt.return (s, v))) next let name cctxt contract = rev_find cctxt contract >|= function - | None -> Contract.to_b48check contract + | None -> Contract.to_b58check contract | Some name -> name end @@ -148,14 +148,14 @@ let commands () = (fun cctxt -> RawContractAlias.load cctxt >>= fun list -> Lwt_list.iter_s (fun (n, v) -> - let v = Contract.to_b48check v in + let v = Contract.to_b58check v in cctxt.message "%s: %s" n v) list >>= fun () -> Client_keys.Public_key_hash.load cctxt >>= fun list -> Lwt_list.iter_s (fun (n, v) -> RawContractAlias.mem cctxt n >>= fun mem -> let p = if mem then "key:" else "" in - let v = Contract.to_b48check (Contract.default_contract v) in + let v = Contract.to_b58check (Contract.default_contract v) in cctxt.message "%s%s: %s" p n v) list >>= fun () -> Lwt.return ()) ; diff --git a/src/client/embedded/bootstrap/client_proto_main.ml b/src/client/embedded/bootstrap/client_proto_main.ml index dbbc47bd3..bd8e989bc 100644 --- a/src/client/embedded/bootstrap/client_proto_main.ml +++ b/src/client/embedded/bootstrap/client_proto_main.ml @@ -8,8 +8,8 @@ (**************************************************************************) let protocol = - Protocol_hash.of_b48check - "4p64VagsbXchSF88eaPy5XrkqMLEjBCaSnaGv2vQkhv8e37Nnqmrd" + Protocol_hash.of_b58check + "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK" let () = Client_commands.register protocol @@ diff --git a/src/client/embedded/bootstrap/webclient/webclient_proto_service_directory.ml b/src/client/embedded/bootstrap/webclient/webclient_proto_service_directory.ml index 5dd2f12c9..e528213ff 100644 --- a/src/client/embedded/bootstrap/webclient/webclient_proto_service_directory.ml +++ b/src/client/embedded/bootstrap/webclient/webclient_proto_service_directory.ml @@ -22,5 +22,5 @@ let root = let root = RPC.register root Services.hash @@ fun block () -> Client_node_rpcs.(call_service1 cctxt Node_rpc_services.Blocks.hash block ()) >>= fun res -> - RPC.Answer.return (Hash.Block_hash.to_b48check res) in + RPC.Answer.return (Hash.Block_hash.to_b58check res) in root diff --git a/src/client/embedded/demo/client_proto_main.ml b/src/client/embedded/demo/client_proto_main.ml index 628b191ef..a74b5e173 100644 --- a/src/client/embedded/demo/client_proto_main.ml +++ b/src/client/embedded/demo/client_proto_main.ml @@ -8,8 +8,8 @@ (**************************************************************************) let protocol = - Protocol_hash.of_b48check - "2gagsSEvTKAHRjxAamgSdBNkv39VtNCqpaDXrrH4K8R4KQAAHrhe3" + Protocol_hash.of_b58check + "ProtoDemoDemoDemoDemoDemoDemoDemoDemoDemoDemoD3c8k9" let demo cctxt = let block = Client_config.block () in diff --git a/src/compiler/tezos_compiler.ml b/src/compiler/tezos_compiler.ml index d3e9c2e64..d81718ddf 100644 --- a/src/compiler/tezos_compiler.ml +++ b/src/compiler/tezos_compiler.ml @@ -266,19 +266,19 @@ let create_register_file client file hash packname modules = create_file file (Printf.sprintf "module Packed_protocol = struct\n\ - \ let hash = (%s.Protocol_hash.of_b48check %S)\n\ + \ let hash = (%s.Protocol_hash.of_b58check %S)\n\ \ type error = %s.error = ..\n\ \ type 'a tzresult = 'a %s.tzresult\n\ \ include %s.%s\n\ \ let error_encoding = %s.error_encoding ()\n\ \ let classify_errors = %s.classify_errors\n\ \ let pp = %s.pp\n\ - \ let complete_b48prefix = %s.complete + \ let complete_b58prefix = %s.complete \ end\n\ \ %s\n\ " hash_module - (Protocol_hash.to_b48check hash) + (Protocol_hash.to_b58check hash) error_monad_module error_monad_module packname (String.capitalize_ascii unit) diff --git a/src/minutils/utils.ml b/src/minutils/utils.ml index 180ccf74e..c2bf5ddec 100644 --- a/src/minutils/utils.ml +++ b/src/minutils/utils.ml @@ -108,6 +108,11 @@ let rec remove_elem_from_list nb = function | l when nb <= 0 -> l | _ :: tl -> remove_elem_from_list (nb - 1) tl +let has_prefix ~prefix s = + let x = String.length prefix in + let n = String.length s in + n >= x && String.sub s 0 x = prefix + let remove_prefix ~prefix s = let x = String.length prefix in let n = String.length s in @@ -116,6 +121,16 @@ let remove_prefix ~prefix s = else None +let common_prefix s1 s2 = + let last = min (String.length s1) (String.length s2) in + let rec loop i = + if last <= i then last + else if s1.[i] = s2.[i] then + loop (i+1) + else + i in + loop 0 + let finalize f g = try let res = f () in g (); res with exn -> g (); raise exn let read_file ?(bin=false) fn = diff --git a/src/minutils/utils.mli b/src/minutils/utils.mli index f43c8433d..b9643cdc0 100644 --- a/src/minutils/utils.mli +++ b/src/minutils/utils.mli @@ -31,7 +31,10 @@ val display_paragraph: Format.formatter -> string -> unit (** [remove nb list] remove the first [nb] elements from the list [list]. *) val remove_elem_from_list: int -> 'a list -> 'a list +val has_prefix: prefix:string -> string -> bool val remove_prefix: prefix:string -> string -> string option +val common_prefix: string -> string -> int + val filter_map: ('a -> 'b option) -> 'a list -> 'b list diff --git a/src/node/db/context.ml b/src/node/db/context.ml index 0d5eea8ba..2770e5bad 100644 --- a/src/node/db/context.ml +++ b/src/node/db/context.ml @@ -82,7 +82,7 @@ let invalid_context_key = ["invalid_context"] let exists (module GitStore : STORE) key = GitStore.of_branch_id - Irmin.Task.none (Block_hash.to_b48check key) GitStore.local_repo >>= fun t -> + Irmin.Task.none (Block_hash.to_b58check key) GitStore.local_repo >>= fun t -> let store = t () in GitStore.read store genesis_block_key >>= function | Some _ -> @@ -102,7 +102,7 @@ let checkout ((module GitStore : STORE) as index) key = Lwt.return None else GitStore.of_branch_id - Irmin.Task.none (Block_hash.to_b48check key) GitStore.local_repo >>= fun t -> + Irmin.Task.none (Block_hash.to_b58check key) GitStore.local_repo >>= fun t -> let store = t () in GitStore.FunView.of_path store [] >>= fun v -> lwt_debug "<- Context.checkout %a OK" @@ -142,7 +142,7 @@ let commit (module GitStore : STORE) block key (module View : VIEW) = let task = Irmin.Task.create ~date:(Time.to_seconds block.Store.shell.timestamp) ~owner:"tezos" in - GitStore.clone task View.s (Block_hash.to_b48check key) >>= function + GitStore.clone task View.s (Block_hash.to_b58check key) >>= function | `Empty_head -> Lwt.fail (Empty_head (GitStore.path, key)) | `Duplicated_branch -> Lwt.fail (Preexistent_context (GitStore.path, key)) | `Ok store -> @@ -157,13 +157,13 @@ let commit_invalid (module GitStore : STORE) block key exns = Irmin.Task.create ~date:(Time.to_seconds block.Store.shell.timestamp) ~owner:"tezos" in GitStore.of_branch_id - task (Block_hash.to_b48check key) GitStore.local_repo >>= fun t -> + task (Block_hash.to_b58check key) GitStore.local_repo >>= fun t -> let msg = Format.asprintf "%a %a" Fitness.pp block.shell.fitness Block_hash.pp_short key in let store = t msg in - GitStore.clone Irmin.Task.none store (Block_hash.to_b48check key) >>= function + GitStore.clone Irmin.Task.none store (Block_hash.to_b58check key) >>= function | `Empty_head -> GitStore.update store invalid_context_key (MBytes.of_string @@ Data_encoding_ezjsonm.to_string @@ @@ -257,7 +257,7 @@ let init ?patch_context ~root = let create_genesis_context (module GitStore : STORE) genesis test_protocol = GitStore.of_branch_id - Irmin.Task.none (Block_hash.to_b48check genesis.Store.block) + Irmin.Task.none (Block_hash.to_b58check genesis.Store.block) GitStore.local_repo >>= fun t -> let store = t () in GitStore.FunView.of_path store [] >>= fun v -> diff --git a/src/node/db/store.ml b/src/node/db/store.ml index 171b1fa54..0690e0576 100644 --- a/src/node/db/store.ml +++ b/src/node/db/store.ml @@ -742,11 +742,11 @@ let net_destroy ~root { net_genesis } = let init root = raw_init ~root:(Filename.concat root "global") () >>= fun t -> - Base48.register_resolver - Block_hash.b48check_encoding + Base58.register_resolver + Block_hash.b58check_encoding (fun s -> Block_resolver.resolve t s); - Base48.register_resolver - Operation_hash.b48check_encoding + Base58.register_resolver + Operation_hash.b58check_encoding (fun s -> Operation_resolver.resolve t s); Lwt.return { block = Persist.share t ; diff --git a/src/node/main/node_run_command.ml b/src/node/main/node_run_command.ml index 4fe3723f7..8ae21c09b 100644 --- a/src/node/main/node_run_command.ml +++ b/src/node/main/node_run_command.ml @@ -13,11 +13,11 @@ let genesis = { Store.time = Time.of_notation_exn "2016-11-01T00:00:00Z" ; block = - Block_hash.of_b48check - "grHGHkVfgJb5gPaRd5AtQsa65g9GyLcXgQsHbSnQ5SD5DEp2ctqck" ; + Block_hash.of_b58check + "BLockGenesisGenesisGenesisGenesisGenesisGeneskvg68z" ; protocol = - Protocol_hash.of_b48check - "4p64VagsbXchSF88eaPy5XrkqMLEjBCaSnaGv2vQkhv8e37Nnqmrd" ; + Protocol_hash.of_b58check + "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK" ; } let (//) = Filename.concat diff --git a/src/node/shell/node.ml b/src/node/shell/node.ml index 6adccc162..9cfb2b335 100644 --- a/src/node/shell/node.ml +++ b/src/node/shell/node.ml @@ -342,8 +342,8 @@ module RPC = struct State.Valid_block.read_exn node.state hash >|= convert let prevalidation_hash = - Block_hash.of_b48check - "eeeeeeeeeeeeeeefcF2dFpTjGjPAxRM3TqDrKkJf7DdkNHpX3DmaD" + Block_hash.of_b58check + "BLockPrevaLidationPrevaLidationPrevaLidationPrZ4mr6" let get_net node = function | `Head _ | `Prevalidation -> node.global_validator, node.global_net @@ -514,15 +514,15 @@ module RPC = struct let complete node ?block str = match block with | None -> - Base48.complete str + Base58.complete str | Some block -> get_context node block >>= function | None -> Lwt.fail Not_found | Some ctxt -> Context.get_protocol ctxt >>= fun protocol_hash -> let (module Proto) = Updater.get_exn protocol_hash in - Base48.complete str >>= fun l1 -> - Proto.complete_b48prefix ctxt str >>= fun l2 -> + Base58.complete str >>= fun l1 -> + Proto.complete_b58prefix ctxt str >>= fun l2 -> Lwt.return (l1 @ l2) let context_dir node block = diff --git a/src/node/shell/node_rpc_services.ml b/src/node/shell/node_rpc_services.ml index b64dd2540..389f6df70 100644 --- a/src/node/shell/node_rpc_services.ml +++ b/src/node/shell/node_rpc_services.ml @@ -102,7 +102,7 @@ module Blocks = struct | ["test_prevalidation"] -> Ok `Test_prevalidation | ["head"; n] -> Ok (`Head (int_of_string n)) | ["test_head"; n] -> Ok (`Test_head (int_of_string n)) - | [h] -> Ok (`Hash (Block_hash.of_b48check h)) + | [h] -> Ok (`Hash (Block_hash.of_b58check h)) | _ -> raise Exit with _ -> Error "Cannot parse block identifier." @@ -124,7 +124,7 @@ module Blocks = struct | `Test_head 0 -> "test_head" | `Test_head n -> Printf.sprintf "test_head~%d" n | `Test_prevalidation -> "test_prevalidation" - | `Hash h -> Block_hash.to_b48check h in + | `Hash h -> Block_hash.to_b58check h in let destruct = parse_block in RPC.Arg.make ~name ~descr ~construct ~destruct () @@ -297,7 +297,7 @@ module Blocks = struct and construct s = s in RPC.Arg.make ~name:"prefix" ~destruct ~construct () in RPC.service - ~description: "Try to complete a prefix of a Base48Check-encoded data. \ + ~description: "Try to complete a prefix of a Base58Check-encoded data. \ This RPC is actually able to complete hashes of \ block, operations, public_keys and contracts." ~input: empty @@ -388,9 +388,9 @@ module Operations = struct let name = "operation_id" in let descr = "A operation identifier in hexadecimal." in - let construct = Operation_hash.to_b48check in + let construct = Operation_hash.to_b58check in let destruct h = - try Ok (Operation_hash.of_b48check h) + try Ok (Operation_hash.of_b58check h) with _ -> Error "Can't parse hash" in RPC.Arg.make ~name ~descr ~construct ~destruct () @@ -439,9 +439,9 @@ module Protocols = struct let name = "protocol_id" in let descr = "A protocol identifier in hexadecimal." in - let construct = Protocol_hash.to_b48check in + let construct = Protocol_hash.to_b58check in let destruct h = - try Ok (Protocol_hash.of_b48check h) + try Ok (Protocol_hash.of_b58check h) with _ -> Error "Can't parse hash" in RPC.Arg.make ~name ~descr ~construct ~destruct () @@ -639,7 +639,7 @@ let complete = and construct s = s in RPC.Arg.make ~name:"prefix" ~destruct ~construct () in RPC.service - ~description: "Try to complete a prefix of a Base48Check-encoded data. \ + ~description: "Try to complete a prefix of a Base58Check-encoded data. \ This RPC is actually able to complete hashes of \ block and hashes of operations." ~input: empty diff --git a/src/node/updater/environment.ml b/src/node/updater/environment.ml index 8705c9814..02a54f585 100644 --- a/src/node/updater/environment.ml +++ b/src/node/updater/environment.ml @@ -25,13 +25,16 @@ module Ed25519 = struct let append_signature key msg = MBytes.concat msg (sign key msg) - module Public_key_hash = Hash.Make_Blake2B(Base48)(struct + module Public_key_hash = Hash.Make_Blake2B(Base58)(struct let name = "Ed25519.Public_key_hash" let title = "An Ed25519 public key ID" - let b48check_prefix = Base48.Prefix.ed25519_public_key_hash + let b58check_prefix = Base58.Prefix.ed25519_public_key_hash let size = Some 20 end) + let () = + Base58.check_encoded_prefix Public_key_hash.b58check_encoding "tz1" 36 + let hash v = Public_key_hash.hash_bytes [ Sodium.Sign.Bigbytes.of_public_key v ] @@ -40,46 +43,54 @@ module Ed25519 = struct let secret, pub = Sodium.Sign.random_keypair () in (hash pub, pub, secret) - type Base48.data += + type Base58.data += | Public_key of public_key | Secret_key of secret_key | Signature of signature - let b48check_public_key_encoding = - Base48.register_encoding - ~prefix: Base48.Prefix.ed25519_public_key + let b58check_public_key_encoding = + Base58.register_encoding + ~prefix: Base58.Prefix.ed25519_public_key + ~length:Sodium.Sign.public_key_size ~to_raw:(fun x -> Bytes.to_string (Sodium.Sign.Bytes.of_public_key x)) ~of_raw:(fun x -> try Some (Sodium.Sign.Bytes.to_public_key (Bytes.of_string x)) with _ -> None) ~wrap:(fun x -> Public_key x) - let b48check_secret_key_encoding = - Base48.register_encoding - ~prefix: Base48.Prefix.ed25519_secret_key + let b58check_secret_key_encoding = + Base58.register_encoding + ~prefix: Base58.Prefix.ed25519_secret_key + ~length:Sodium.Sign.secret_key_size ~to_raw:(fun x -> Bytes.to_string (Sodium.Sign.Bytes.of_secret_key x)) ~of_raw:(fun x -> try Some (Sodium.Sign.Bytes.to_secret_key (Bytes.of_string x)) with _ -> None) ~wrap:(fun x -> Secret_key x) - let b48check_signature_encoding = - Base48.register_encoding - ~prefix: Base48.Prefix.ed25519_signature + let b58check_signature_encoding = + Base58.register_encoding + ~prefix: Base58.Prefix.ed25519_signature + ~length:Sodium.Sign.signature_size ~to_raw:MBytes.to_string ~of_raw:(fun s -> Some (MBytes.of_string s)) ~wrap:(fun x -> Signature x) + let () = + Base58.check_encoded_prefix b58check_public_key_encoding "edpk" 54 ; + Base58.check_encoded_prefix b58check_secret_key_encoding "edsk" 98 ; + Base58.check_encoded_prefix b58check_signature_encoding "edsig" 99 + let public_key_encoding = let open Data_encoding in splitted ~json: (describe - ~title: "An Ed25519 public key (Base48Check encoded)" @@ + ~title: "An Ed25519 public key (Base58Check encoded)" @@ conv - (fun s -> Base48.simple_encode b48check_public_key_encoding s) + (fun s -> Base58.simple_encode b58check_public_key_encoding s) (fun s -> - match Base48.simple_decode b48check_public_key_encoding s with + match Base58.simple_decode b58check_public_key_encoding s with | Some x -> x | None -> Data_encoding.Json.cannot_destruct "Ed25519 public key: unexpected prefix.") @@ -95,11 +106,11 @@ module Ed25519 = struct splitted ~json: (describe - ~title: "An Ed25519 secret key (Base48Check encoded)" @@ + ~title: "An Ed25519 secret key (Base58Check encoded)" @@ conv - (fun s -> Base48.simple_encode b48check_secret_key_encoding s) + (fun s -> Base58.simple_encode b58check_secret_key_encoding s) (fun s -> - match Base48.simple_decode b48check_secret_key_encoding s with + match Base58.simple_decode b58check_secret_key_encoding s with | Some x -> x | None -> Data_encoding.Json.cannot_destruct "Ed25519 secret key: unexpected prefix.") @@ -115,11 +126,11 @@ module Ed25519 = struct splitted ~json: (describe - ~title: "An Ed25519 signature (Base48Check encoded)" @@ + ~title: "An Ed25519 signature (Base58Check encoded)" @@ conv - (fun s -> Base48.simple_encode b48check_signature_encoding s) + (fun s -> Base58.simple_encode b58check_signature_encoding s) (fun s -> - match Base48.simple_decode b48check_signature_encoding s with + match Base58.simple_decode b58check_signature_encoding s with | Some x -> x | None -> Data_encoding.Json.cannot_destruct "Ed25519 signature: unexpected prefix.") @@ -171,14 +182,17 @@ module Make(Param : sig val name: string end)() = struct include Error_monad.Make() end module Logging = Logging.Make(Param) - module Base48 = struct - include Base48 + module Base58 = struct + include Base58 + let simple_encode enc s = simple_encode enc s + let simple_decode enc s = simple_decode enc s include Make(struct type context = Context.t end) + let decode s = decode s end module Context = struct include Context - let register_resolver = Base48.register_resolver - let complete = Base48.complete + let register_resolver = Base58.register_resolver + let complete ctxt s = Base58.complete ctxt s end module type PACKED_PROTOCOL = sig @@ -187,8 +201,7 @@ module Make(Param : sig val name: string end)() = struct val error_encoding : error Data_encoding.t val classify_errors : error list -> [ `Branch | `Temporary | `Permanent ] val pp : Format.formatter -> error -> unit - val complete_b48prefix : - ?alphabet:string -> Context.t -> string -> string list Lwt.t + val complete_b58prefix : Context.t -> string -> string list Lwt.t end end diff --git a/src/node/updater/environment_gen.ml b/src/node/updater/environment_gen.ml index 99fab1063..e1e175f87 100644 --- a/src/node/updater/environment_gen.ml +++ b/src/node/updater/environment_gen.ml @@ -55,8 +55,7 @@ module type PACKED_PROTOCOL = sig val error_encoding : error Data_encoding.t val classify_errors : error list -> [ `Branch | `Temporary | `Permanent ] val pp : Format.formatter -> error -> unit - val complete_b48prefix : - ?alphabet:string -> Context.t -> string -> string list Lwt.t + val complete_b58prefix : Context.t -> string -> string list Lwt.t end val __cast: (module PACKED_PROTOCOL) -> (module Protocol.PACKED_PROTOCOL) |} diff --git a/src/node/updater/protocol.mli b/src/node/updater/protocol.mli index 3d3ea57a3..35b1c3864 100644 --- a/src/node/updater/protocol.mli +++ b/src/node/updater/protocol.mli @@ -135,6 +135,5 @@ module type PACKED_PROTOCOL = sig val error_encoding : error Data_encoding.t val classify_errors : error list -> [ `Branch | `Temporary | `Permanent ] val pp : Format.formatter -> error -> unit - val complete_b48prefix : - ?alphabet:string -> Context.t -> string -> string list Lwt.t + val complete_b58prefix : Context.t -> string -> string list Lwt.t end diff --git a/src/node/updater/updater.ml b/src/node/updater/updater.ml index 4e9ce4ed0..c5b32bb01 100644 --- a/src/node/updater/updater.ml +++ b/src/node/updater/updater.ml @@ -16,8 +16,7 @@ module type REGISTRED_PROTOCOL = sig val hash: Protocol_hash.t include Protocol.PROTOCOL with type error := error and type 'a tzresult := 'a tzresult - val complete_b48prefix : - ?alphabet:string -> Context.t -> string -> string list Lwt.t + val complete_b58prefix : Context.t -> string -> string list Lwt.t end type net_id = Store.net_id = Net of Block_hash.t @@ -158,16 +157,16 @@ let create_files dir units = Lwt.return files let extract dirname hash units = - let source_dir = dirname // Protocol_hash.to_short_b48check hash // "src" in + let source_dir = dirname // Protocol_hash.to_short_b58check hash // "src" in create_files source_dir units >|= fun _files -> Tezos_compiler.Meta.to_file source_dir ~hash (List.map (fun {name} -> String.capitalize_ascii name) units) let do_compile hash units = let datadir = get_datadir () in - let source_dir = datadir // Protocol_hash.to_short_b48check hash // "src" in - let log_file = datadir // Protocol_hash.to_short_b48check hash // "LOG" in - let plugin_file = datadir // Protocol_hash.to_short_b48check hash // + let source_dir = datadir // Protocol_hash.to_short_b58check hash // "src" in + let log_file = datadir // Protocol_hash.to_short_b58check hash // "LOG" in + let plugin_file = datadir // Protocol_hash.to_short_b58check hash // Format.asprintf "protocol_%a.cmxs" Protocol_hash.pp hash in create_files source_dir units >>= fun _files -> diff --git a/src/node/updater/updater.mli b/src/node/updater/updater.mli index aaad9c544..ba891829c 100644 --- a/src/node/updater/updater.mli +++ b/src/node/updater/updater.mli @@ -68,8 +68,7 @@ module type REGISTRED_PROTOCOL = sig (* exception Ecoproto_error of error list *) include Protocol.PROTOCOL with type error := error and type 'a tzresult := 'a tzresult - val complete_b48prefix : - ?alphabet:string -> Context.t -> string -> string list Lwt.t + val complete_b58prefix : Context.t -> string -> string list Lwt.t end type component = Tezos_compiler.Protocol.component = { diff --git a/src/proto/bootstrap/TEZOS_PROTOCOL b/src/proto/bootstrap/TEZOS_PROTOCOL index eb1c26ea6..787ccb742 100644 --- a/src/proto/bootstrap/TEZOS_PROTOCOL +++ b/src/proto/bootstrap/TEZOS_PROTOCOL @@ -1,5 +1,5 @@ { - "hash": "4p64VagsbXchSF88eaPy5XrkqMLEjBCaSnaGv2vQkhv8e37Nnqmrd", + "hash": "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK", "modules": [ "Misc", diff --git a/src/proto/bootstrap/contract_repr.ml b/src/proto/bootstrap/contract_repr.ml index 136fc03ea..cca8ce94f 100644 --- a/src/proto/bootstrap/contract_repr.ml +++ b/src/proto/bootstrap/contract_repr.ml @@ -24,12 +24,12 @@ type contract = t type error += Invalid_contract_notation of string -let to_b48check = function - | Default pbk -> Ed25519.Public_key_hash.to_b48check pbk - | Hash h -> Contract_hash.to_b48check h +let to_b58check = function + | Default pbk -> Ed25519.Public_key_hash.to_b58check pbk + | Hash h -> Contract_hash.to_b58check h -let of_b48check s = - match Base48.decode s with +let of_b58check s = + match Base58.decode s with | Some (Ed25519.Public_key_hash.Hash h) -> ok (Default h) | Some (Contract_hash.Hash h) -> ok (Hash h) | _ -> error (Invalid_contract_notation s) @@ -57,9 +57,9 @@ let encoding = ]) ~json: (conv - to_b48check + to_b58check (fun s -> - match of_b48check s with + match of_b58check s with | Ok s -> s | Error _ -> Json.cannot_destruct "Invalid contract notation.") string) @@ -113,13 +113,13 @@ let generic_contract ~manager ~delegate ~spendable ~delegatable ~script = Hash (Contract_hash.hash_bytes [data]) let arg = - let construct = to_b48check in + let construct = to_b58check in let destruct hash = - match of_b48check hash with + match of_b58check hash with | Error _ -> Error "Cannot parse contract id" | Ok contract -> Ok contract in RPC.Arg.make - ~descr: "A contract identifier encoded in b48check." + ~descr: "A contract identifier encoded in b58check." ~name: "contract_id" ~construct ~destruct diff --git a/src/proto/bootstrap/contract_repr.mli b/src/proto/bootstrap/contract_repr.mli index 2422f268e..adf28907b 100644 --- a/src/proto/bootstrap/contract_repr.mli +++ b/src/proto/bootstrap/contract_repr.mli @@ -40,9 +40,9 @@ val generic_contract : type error += Invalid_contract_notation of string -val to_b48check: contract -> string +val to_b58check: contract -> string -val of_b48check: string -> contract tzresult +val of_b58check: string -> contract tzresult (** {2 Serializers} ***********************************************************) diff --git a/src/proto/bootstrap/contract_storage.ml b/src/proto/bootstrap/contract_storage.ml index 4d3d0efe8..97dfa8cd1 100644 --- a/src/proto/bootstrap/contract_storage.ml +++ b/src/proto/bootstrap/contract_storage.ml @@ -42,7 +42,7 @@ let () = ~pp:(fun ppf (contract, exp, found) -> Format.fprintf ppf "Unexpected counter %ld for contract %s (expected %ld)" - found (Contract_repr.to_b48check contract) exp) + found (Contract_repr.to_b58check contract) exp) Data_encoding. (obj3 (req "contract" Contract_repr.encoding) @@ -309,4 +309,4 @@ let init c = Storage.Contract.Global_counter.init c 0l let pp fmt c = - Format.pp_print_string fmt (Contract_repr.to_b48check c) + Format.pp_print_string fmt (Contract_repr.to_b58check c) diff --git a/src/proto/bootstrap/script_ir_translator.ml b/src/proto/bootstrap/script_ir_translator.ml index a40df1cf6..1cf2f3b50 100644 --- a/src/proto/bootstrap/script_ir_translator.ml +++ b/src/proto/bootstrap/script_ir_translator.ml @@ -300,7 +300,7 @@ let rec unparse_data | Timestamp_t, t -> String (-1, Timestamp.to_notation t) | Contract_t _, (_, _, c) -> - String (-1, Contract.to_b48check c) + String (-1, Contract.to_b58check c) | Signature_t, s -> let text = Hex_encode.hex_encode @@ -309,7 +309,7 @@ let rec unparse_data | Tez_t, v -> String (-1, Tez.to_string v) | Key_t, k -> - String (-1, Ed25519.Public_key_hash.to_b48check k) + String (-1, Ed25519.Public_key_hash.to_b58check k) | Pair_t (tl, tr), (l, r) -> let l = unparse_data tl l in let r = unparse_data tr r in @@ -671,7 +671,7 @@ let rec parse_data traced (fail (Invalid_kind (location expr, [ String_kind ; Int_kind ], kind expr))) (* IDs *) | Key_t, String (_, s) -> begin try - return (Ed25519.Public_key_hash.of_b48check s) + return (Ed25519.Public_key_hash.of_b58check s) with _ -> fail (error ()) end | Key_t, expr -> @@ -691,7 +691,7 @@ let rec parse_data (* Contracts *) | Contract_t (ty1, ty2), String (loc, s) -> traced @@ - (Lwt.return (Contract.of_b48check s)) >>=? fun c -> + (Lwt.return (Contract.of_b58check s)) >>=? fun c -> parse_contract ctxt ty1 ty2 loc c >>=? fun _ -> return (ty1, ty2, c) | Contract_t _, expr -> diff --git a/src/proto/bootstrap/script_repr.ml b/src/proto/bootstrap/script_repr.ml index a77cf9e04..ab7a4f627 100644 --- a/src/proto/bootstrap/script_repr.ml +++ b/src/proto/bootstrap/script_repr.ml @@ -137,7 +137,7 @@ let code_encoding = let hash_expr data = let bytes = Data_encoding.Binary.to_bytes expr_encoding data in - Script_expr_hash.(hash_bytes [ bytes ] |> to_b48check) + Script_expr_hash.(hash_bytes [ bytes ] |> to_b58check) type t = | No_script diff --git a/src/proto/bootstrap/services.ml b/src/proto/bootstrap/services.ml index 15607e5ee..b8141b172 100644 --- a/src/proto/bootstrap/services.ml +++ b/src/proto/bootstrap/services.ml @@ -177,9 +177,9 @@ module Context = struct module Key = struct let public_key_hash_arg = - let construct = Ed25519.Public_key_hash.to_b48check in + let construct = Ed25519.Public_key_hash.to_b58check in let destruct hash = - match Ed25519.Public_key_hash.of_b48check hash with + match Ed25519.Public_key_hash.of_b58check hash with | exception _ -> Error "Cannot parse public key hash" | public_key_hash -> Ok public_key_hash in RPC.Arg.make diff --git a/src/proto/bootstrap/storage_functors.ml b/src/proto/bootstrap/storage_functors.ml index a6af8dbff..a1f467a4f 100644 --- a/src/proto/bootstrap/storage_functors.ml +++ b/src/proto/bootstrap/storage_functors.ml @@ -377,6 +377,6 @@ let register_resolvers (module H : Hash.HASH) prefixes = Set.empty hs |> Set.elements in - Context.register_resolver H.b48check_encoding resolve + Context.register_resolver H.b58check_encoding resolve diff --git a/src/proto/bootstrap/tezos_context.mli b/src/proto/bootstrap/tezos_context.mli index 1f29a1e05..f55298a84 100644 --- a/src/proto/bootstrap/tezos_context.mli +++ b/src/proto/bootstrap/tezos_context.mli @@ -308,8 +308,8 @@ module Contract : sig type contract = t val arg: contract RPC.Arg.arg - val to_b48check: contract -> string - val of_b48check: string -> contract tzresult + val to_b58check: contract -> string + val of_b58check: string -> contract tzresult val default_contract: public_key_hash -> contract val is_default: contract -> public_key_hash option diff --git a/src/proto/bootstrap/tezos_hash.ml b/src/proto/bootstrap/tezos_hash.ml index 5865e4e1e..9ffb966f7 100644 --- a/src/proto/bootstrap/tezos_hash.ml +++ b/src/proto/bootstrap/tezos_hash.ml @@ -8,48 +8,55 @@ (**************************************************************************) module Prefix = struct - let make x = - assert (Compare.String.(Base48.Prefix.protocol_prefix = "\015")) ; - String.make 1 (char_of_int ((x lsl 4) lor 15)) - let public_key_hash = make 0 - let contract_hash = make 1 - let nonce_hash = make 2 - let script_expr_hash = make 3 - let random_state_hash = make 15 (* never used... *) + + (* 20 *) + let contract_hash = "\003\099\029" (* TZ(36) *) + + (* 32 *) + let nonce_hash = "\069\220\169" (* nce(53) *) + let script_expr_hash = "\013\044\064\027" (* expr(54) *) + let random_state_hash = "\076\064\204" (* rng(53): never used... *) + end -module State_hash = Hash.Make_Blake2B(Base48)(struct +module State_hash = Hash.Make_Blake2B(Base58)(struct let name = "random" let title = "A random generation state" - let b48check_prefix = Prefix.random_state_hash + let b58check_prefix = Prefix.random_state_hash let size = None end) module State_hash_set = Hash_set(State_hash) module State_hash_map = Hash_map(State_hash) -module Nonce_hash = Hash.Make_Blake2B(Base48)(struct +module Nonce_hash = Hash.Make_Blake2B(Base58)(struct let name = "cycle_nonce" let title = "A nonce hash" - let b48check_prefix = Prefix.nonce_hash + let b58check_prefix = Prefix.nonce_hash let size = None end) module Nonce_hash_set = Hash_set(Nonce_hash) module Nonce_hash_map = Hash_map(Nonce_hash) -module Script_expr_hash = Hash.Make_Blake2B(Base48)(struct +module Script_expr_hash = Hash.Make_Blake2B(Base58)(struct let name = "script_expr" let title = "A script expression ID" - let b48check_prefix = Prefix.script_expr_hash + let b58check_prefix = Prefix.script_expr_hash let size = None end) module Script_expr_hash_set = Hash_set(Script_expr_hash) module Script_expr_hash_map = Hash_map(Script_expr_hash) -module Contract_hash = Hash.Make_Blake2B(Base48)(struct +module Contract_hash = Hash.Make_Blake2B(Base58)(struct let name = "Contract_hash" let title = "A contract ID" - let b48check_prefix = Prefix.contract_hash + let b58check_prefix = Prefix.contract_hash let size = Some 20 end) module Contract_hash_set = Hash_set(Contract_hash) module Contract_hash_map = Hash_map(Contract_hash) + +let () = + Base58.check_encoded_prefix Contract_hash.b58check_encoding "TZ1" 36 ; + Base58.check_encoded_prefix Script_expr_hash.b58check_encoding "expr" 54 ; + Base58.check_encoded_prefix Nonce_hash.b58check_encoding "nce" 53 ; + Base58.check_encoded_prefix State_hash.b58check_encoding "rng" 53 diff --git a/src/proto/demo/TEZOS_PROTOCOL b/src/proto/demo/TEZOS_PROTOCOL index fd219fffb..f8b496a9f 100644 --- a/src/proto/demo/TEZOS_PROTOCOL +++ b/src/proto/demo/TEZOS_PROTOCOL @@ -1,4 +1,4 @@ { - "hash": "2gagsSEvTKAHRjxAamgSdBNkv39VtNCqpaDXrrH4K8R4KQAAHrhe3", + "hash": "ProtoDemoDemoDemoDemoDemoDemoDemoDemoDemoDemoD3c8k9", "modules": ["Error", "Services", "Main"] } diff --git a/src/proto/environment/base48.mli b/src/proto/environment/base48.mli deleted file mode 100644 index ba3cc3733..000000000 --- a/src/proto/environment/base48.mli +++ /dev/null @@ -1,20 +0,0 @@ - -module Prefix : sig - val protocol_prefix: string -end - -type 'a encoding - -val simple_decode: ?alphabet:string -> 'a encoding -> string -> 'a option -val simple_encode: ?alphabet:string -> 'a encoding -> 'a -> string - -type data = .. - -val register_encoding: - prefix: string -> - to_raw: ('a -> string) -> - of_raw: (string -> 'a option) -> - wrap: ('a -> data) -> - 'a encoding - -val decode: ?alphabet:string -> string -> data option diff --git a/src/proto/environment/base58.mli b/src/proto/environment/base58.mli new file mode 100644 index 000000000..d54f6a812 --- /dev/null +++ b/src/proto/environment/base58.mli @@ -0,0 +1,19 @@ + +type 'a encoding + +val simple_decode: 'a encoding -> string -> 'a option +val simple_encode: 'a encoding -> 'a -> string + +type data = .. + +val register_encoding: + prefix: string -> + length: int -> + to_raw: ('a -> string) -> + of_raw: (string -> 'a option) -> + wrap: ('a -> data) -> + 'a encoding + +val check_encoded_prefix: 'a encoding -> string -> int -> unit + +val decode: string -> data option diff --git a/src/proto/environment/context.mli b/src/proto/environment/context.mli index a2e895dcf..762ea90eb 100644 --- a/src/proto/environment/context.mli +++ b/src/proto/environment/context.mli @@ -9,7 +9,6 @@ val get_genesis_time: t -> Time.t Lwt.t val get_genesis_block: t -> Block_hash.t Lwt.t val register_resolver: - 'a Base48.encoding -> (t -> string -> 'a list Lwt.t) -> unit + 'a Base58.encoding -> (t -> string -> 'a list Lwt.t) -> unit -val complete: - ?alphabet:string -> t -> string -> string list Lwt.t +val complete: t -> string -> string list Lwt.t diff --git a/src/proto/environment/hash.mli b/src/proto/environment/hash.mli index 5a8bb1bda..f1c08f223 100644 --- a/src/proto/environment/hash.mli +++ b/src/proto/environment/hash.mli @@ -40,14 +40,14 @@ module type HASH = sig include MINIMAL_HASH - val of_b48check: string -> t - val to_b48check: t -> string - val to_short_b48check: t -> string + val of_b58check: string -> t + val to_b58check: t -> string + val to_short_b58check: t -> string val encoding: t Data_encoding.t val pp: Format.formatter -> t -> unit val pp_short: Format.formatter -> t -> unit - type Base48.data += Hash of t - val b48check_encoding: t Base48.encoding + type Base58.data += Hash of t + val b58check_encoding: t Base58.encoding end @@ -65,7 +65,7 @@ end module type PrefixedName = sig include Name - val b48check_prefix : string + val b58check_prefix : string end (** Builds a new Hash type using Sha256. *) @@ -75,10 +75,11 @@ module Make_Blake2B (Register : sig val register_encoding: prefix: string -> + length: int -> to_raw: ('a -> string) -> of_raw: (string -> 'a option) -> - wrap: ('a -> Base48.data) -> - 'a Base48.encoding + wrap: ('a -> Base58.data) -> + 'a Base58.encoding end) (Name : PrefixedName) : HASH diff --git a/src/utils/base48.ml b/src/utils/base48.ml deleted file mode 100644 index b9b1345b8..000000000 --- a/src/utils/base48.ml +++ /dev/null @@ -1,238 +0,0 @@ -(**************************************************************************) -(* *) -(* Copyright (c) 2014 - 2016. *) -(* Dynamic Ledger Solutions, Inc. *) -(* *) -(* All rights reserved. No warranty, explicit or implicit, provided. *) -(* *) -(**************************************************************************) - -open Utils - -let (>>=) = Lwt.bind -let (>|=) = Lwt.(>|=) - -let decode_alphabet alphabet = - let str = Bytes.make 256 '\255' in - for i = 0 to String.length alphabet - 1 do - Bytes.set str (int_of_char alphabet.[i]) (char_of_int i) ; - done ; - Bytes.to_string str - -let default_alphabet = - "eE2NXaQvHPqDdTJxfF36jb7VRmp9tAyMgG4L5cS8CKrnksBh" - -let default_decode_alphabet = decode_alphabet default_alphabet - -let count_trailing_char s c = - let len = String.length s in - let rec loop i = - if i < 0 then len - else if String.get s i <> c then (len-i-1) - else loop (i-1) in - loop (len-1) - -let of_char ?(alphabet=default_decode_alphabet) x = - let pos = String.get alphabet (int_of_char x) in - if pos = '\255' then failwith "Invalid data" ; - int_of_char pos - -let to_char ?(alphabet=default_alphabet) x = - alphabet.[x] - -let forty_eight = Z.of_int 48 - -let raw_encode ?alphabet s = - let zero, alphabet = - match alphabet with - | None -> default_alphabet.[0], default_alphabet - | Some alphabet -> - if String.length alphabet <> 48 then invalid_arg "Base48.encode" ; - alphabet.[0], decode_alphabet alphabet in - let zeros = count_trailing_char s '\000' in - let len = String.length s in - let res_len = (len * 8 + 4) / 5 in - let res = Bytes.make res_len '\000' in - let s = Z.of_bits s in - let rec loop s i = - if s = Z.zero then i else - let s, r = Z.div_rem s forty_eight in - Bytes.set res i (to_char ~alphabet (Z.to_int r)); - loop s (i+1) in - let i = loop s 0 in - let res = Bytes.sub_string res 0 i in - res ^ String.make zeros zero - -let raw_decode ?alphabet s = - let zero, alphabet = - match alphabet with - | None -> default_alphabet.[0], default_decode_alphabet - | Some alphabet -> - if String.length alphabet <> 48 then invalid_arg "Base48.decode" ; - alphabet.[0], decode_alphabet alphabet in - let zeros = count_trailing_char s zero in - let len = String.length s in - let rec loop res i = - if i < 0 then res else - let x = Z.of_int (of_char ~alphabet (String.get s i)) in - let res = Z.(add x (mul res forty_eight)) in - loop res (i-1) - in - let res = Z.to_bits @@ loop Z.zero (len - zeros - 1) in - let res_tzeros = count_trailing_char res '\000' in - String.sub res 0 (String.length res - res_tzeros) ^ - String.make zeros '\000' - -let checksum s = - let bytes = Bytes.of_string s in - let hash = - let open Sodium.Generichash in - let state = init ~size:32 () in - Bytes.update state bytes ; - Bytes.of_hash (final state) in - Bytes.sub_string hash 0 4 - -(* Prepend a 4 bytes cryptographic checksum before encoding string s *) -let safe_encode ?alphabet s = - raw_encode ?alphabet (s ^ checksum s) - -let safe_decode ?alphabet s = - let s = raw_decode ?alphabet s in - let len = String.length s in - let msg = String.sub s 0 (len-4) - and msg_hash = String.sub s (len-4) 4 in - if msg_hash <> checksum msg then - invalid_arg "safe_decode" ; - msg - -type data = .. - -type 'a encoding = { - prefix: string; - to_raw: 'a -> string ; - of_raw: string -> 'a option ; - wrap: 'a -> data ; -} - -let simple_decode ?alphabet { prefix ; of_raw } s = - safe_decode ?alphabet s |> - remove_prefix ~prefix |> - Utils.apply_option ~f:of_raw - -let simple_encode ?alphabet { prefix ; to_raw } d = - safe_encode ?alphabet (prefix ^ to_raw d) - -type registred_encoding = Encoding : 'a encoding -> registred_encoding - -module MakeEncodings(E: sig - val encodings: registred_encoding list - end) = struct - - let encodings = ref E.encodings - - let ambiguous_prefix prefix encodings = - List.exists (fun (Encoding { prefix = s }) -> - remove_prefix s prefix <> None || - remove_prefix prefix s <> None) - encodings - - let register_encoding ~prefix ~to_raw ~of_raw ~wrap = - if ambiguous_prefix prefix !encodings then - Format.ksprintf invalid_arg - "Base48.register_encoding: duplicate prefix: %S" prefix ; - let encoding = { prefix ; to_raw ; of_raw ; wrap } in - encodings := Encoding encoding :: !encodings ; - encoding - - let decode ?alphabet s = - let rec find s = function - | [] -> None - | Encoding { prefix ; of_raw ; wrap } :: encodings -> - match remove_prefix ~prefix s with - | None -> find s encodings - | Some msg -> of_raw msg |> Utils.map_option ~f:wrap in - let s = safe_decode ?alphabet s in - find s !encodings - -end - -type 'a resolver = - Resolver : { - encoding: 'h encoding ; - resolver: 'a -> string -> 'h list Lwt.t ; - } -> 'a resolver - -module MakeResolvers(R: sig - type context - val encodings: registred_encoding list ref - end) = struct - - let resolvers = ref [] - - let register_resolver - (type a) - (encoding : a encoding) - (resolver : R.context -> string -> a list Lwt.t) = - try - resolvers := Resolver { encoding ; resolver } :: !resolvers - with Not_found -> - invalid_arg "Base48.register_resolver: unregistred encodings" - - type context = R.context - - let complete ?alphabet context request = - (* One may extract from the prefix of a Base48-encoded value, a - prefix of the original encoded value. Given that `48 = 3 * 2^4`, - every "digits" in the Base48-prefix (i.e. a "bytes" in its ascii - representation), provides for sure 4 bits of the original data. - Hence, when we decode a prefix of a Base48-encoded value of - length `n`, the `n/2` first bytes of the decoded value are (for - sure) a prefix of the original value. *) - let n = String.length request in - let s = raw_decode request ?alphabet in - let partial = String.sub s 0 (n / 2) in - let rec find s = function - | [] -> Lwt.return_nil - | Resolver { encoding ; resolver } :: resolvers -> - match remove_prefix ~prefix:encoding.prefix s with - | None -> find s resolvers - | Some msg -> - resolver context msg >|= fun msgs -> - filter_map - (fun msg -> - let res = simple_encode encoding ?alphabet msg in - Utils.remove_prefix ~prefix:request res |> - Utils.map_option ~f:(fun _ -> res)) - msgs in - find partial !resolvers - -end - -include MakeEncodings(struct let encodings = [] end) -include MakeResolvers(struct - type context = unit - let encodings = encodings - end) - -let register_resolver enc f = register_resolver enc (fun () s -> f s) -let complete ?alphabet s = complete ?alphabet () s - -module Make(C: sig type context end) = struct - include MakeEncodings(struct let encodings = !encodings end) - include MakeResolvers(struct - type context = C.context - let encodings = encodings - end) -end - -module Prefix = struct - let block_hash = "\000" - let operation_hash = "\001" - let protocol_hash = "\002" - let ed25519_public_key_hash = "\003" - let cryptobox_public_key_hash = "\004" - let ed25519_public_key = "\012" - let ed25519_secret_key = "\013" - let ed25519_signature = "\014" - let protocol_prefix = "\015" -end diff --git a/src/utils/base58.ml b/src/utils/base58.ml new file mode 100644 index 000000000..e66f8ab9d --- /dev/null +++ b/src/utils/base58.ml @@ -0,0 +1,312 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2016. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +open Utils +open Lwt.Infix + +let base = 58 +let zbase = Z.of_int base + +let log2 x = log x /. log 2. +let log2_base = log2 (float_of_int base) + + +module Alphabet = struct + + type t = { encode: string ; decode: string } + + let make alphabet = + if String.length alphabet <> base then + invalid_arg "Base58: invalid alphabet (length)" ; + let str = Bytes.make 256 '\255' in + for i = 0 to String.length alphabet - 1 do + let char = int_of_char alphabet.[i] in + if Bytes.get str char <> '\255' then + Format.kasprintf invalid_arg + "Base58: invalid alphabet (dup '%c' %d %d)" + (char_of_int char) (int_of_char @@ Bytes.get str char) i ; + Bytes.set str char (char_of_int i) ; + done ; + { encode = alphabet ; decode = Bytes.to_string str } + + let bitcoin = + make "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" + let ripple = + make "rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz" + let flickr = + make "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ" + + let default = bitcoin + +end + +let count_trailing_char s c = + let len = String.length s in + let rec loop i = + if i < 0 then len + else if String.get s i <> c then (len-i-1) + else loop (i-1) in + loop (len-1) + +let count_leading_char s c = + let len = String.length s in + let rec loop i = + if i = len then len + else if String.get s i <> c then i + else loop (i+1) in + loop 0 + +let of_char ?(alphabet=Alphabet.default) x = + let pos = String.get alphabet.decode (int_of_char x) in + if pos = '\255' then failwith "Invalid data" ; + int_of_char pos + +let to_char ?(alphabet=Alphabet.default) x = + alphabet.encode.[x] + +let raw_encode ?(alphabet=Alphabet.default) s = + let len = String.length s in + let s = String.init len (fun i -> String.get s (len - i - 1)) in + let zero = alphabet.encode.[0] in + let zeros = count_trailing_char s '\000' in + let res_len = (len * 8 + 4) / 5 in + let res = Bytes.make res_len '\000' in + let s = Z.of_bits s in + let rec loop s = + if s = Z.zero then 0 else + let s, r = Z.div_rem s zbase in + let i = loop s in + Bytes.set res i (to_char ~alphabet (Z.to_int r)) ; + i + 1 in + let i = loop s in + let res = Bytes.sub_string res 0 i in + String.make zeros zero ^ res + +let raw_decode ?(alphabet=Alphabet.default) s = + let zero = alphabet.encode.[0] in + let zeros = count_leading_char s zero in + let len = String.length s in + let rec loop res i = + if i = len then res else + let x = Z.of_int (of_char ~alphabet (String.get s i)) in + let res = Z.(add x (mul res zbase)) in + loop res (i+1) + in + let res = Z.to_bits @@ loop Z.zero zeros in + let res_tzeros = count_trailing_char res '\000' in + let len = String.length res - res_tzeros in + String.make zeros '\000' ^ + String.init len (fun i -> String.get res (len - i - 1)) + +let checksum s = + let hash = + Nocrypto.Hash.digest `SHA256 @@ + Nocrypto.Hash.digest `SHA256 @@ + Cstruct.of_string s in + let res = Bytes.make 4 '\000' in + Cstruct.blit_to_bytes hash 0 res 0 4 ; + Bytes.to_string res + +(* Append a 4-bytes cryptographic checksum before encoding string s *) +let safe_encode ?alphabet s = + raw_encode ?alphabet (s ^ checksum s) + +let safe_decode ?alphabet s = + let s = raw_decode ?alphabet s in + let len = String.length s in + let msg = String.sub s 0 (len-4) + and msg_hash = String.sub s (len-4) 4 in + if msg_hash <> checksum msg then + invalid_arg "safe_decode" ; + msg + +type data = .. + +type 'a encoding = { + prefix: string ; + length: int ; + encoded_prefix: string ; + encoded_length: int ; + to_raw: 'a -> string ; + of_raw: string -> 'a option ; + wrap: 'a -> data ; +} + +let simple_decode ?alphabet { prefix ; of_raw } s = + safe_decode ?alphabet s |> + remove_prefix ~prefix |> + Utils.apply_option ~f:of_raw + +let simple_encode ?alphabet { prefix ; to_raw } d = + safe_encode ?alphabet (prefix ^ to_raw d) + +type registred_encoding = Encoding : 'a encoding -> registred_encoding + +module MakeEncodings(E: sig + val encodings: registred_encoding list + end) = struct + + let encodings = ref E.encodings + + let check_ambiguous_prefix prefix encodings = + List.iter + (fun (Encoding { encoded_prefix = s }) -> + if remove_prefix s prefix <> None || + remove_prefix prefix s <> None then + Format.ksprintf invalid_arg + "Base58.register_encoding: duplicate prefix: %S, %S." s prefix) + encodings + + let make_encoded_prefix prefix len = + let zeros = safe_encode (prefix ^ String.make len '\000') + and ones = safe_encode (prefix ^ String.make len '\255') in + let len = String.length zeros in + if String.length ones <> len then + Format.ksprintf invalid_arg + "Base58.registred_encoding: variable length encoding." ; + let rec loop i = + if i = len then len + else if zeros.[i] = ones.[i] then loop (i+1) + else i in + let len = loop 0 in + if len = 0 then + invalid_arg + "Base58.register_encoding: not a unique prefix." ; + String.sub zeros 0 len, String.length zeros + + let register_encoding ~prefix ~length ~to_raw ~of_raw ~wrap = + let to_raw x = + let s = to_raw x in assert (String.length s = length) ; s in + let of_raw s = assert (String.length s = length) ; of_raw s in + let encoded_prefix, encoded_length = make_encoded_prefix prefix length in + check_ambiguous_prefix encoded_prefix !encodings ; + let encoding = + { prefix ; length ; encoded_prefix ; encoded_length ; + to_raw ; of_raw ; wrap } in + encodings := Encoding encoding :: !encodings ; + encoding + + let check_encoded_prefix enc p l = + if enc.encoded_prefix <> p then + Format.kasprintf failwith + "Unexpected prefix %s (expected %s)" + p enc.encoded_prefix ; + if enc.encoded_length <> l then + Format.kasprintf failwith + "Unexpected encoded length %d for %s (expected %d)" + l p enc.encoded_length + + let decode ?alphabet s = + let rec find s = function + | [] -> None + | Encoding { prefix ; of_raw ; wrap } :: encodings -> + match remove_prefix ~prefix s with + | None -> find s encodings + | Some msg -> of_raw msg |> Utils.map_option ~f:wrap in + let s = safe_decode ?alphabet s in + find s !encodings + +end + +type 'a resolver = + Resolver : { + encoding: 'h encoding ; + resolver: 'a -> string -> 'h list Lwt.t ; + } -> 'a resolver + +module MakeResolvers(R: sig + type context + val encodings: registred_encoding list ref + end) = struct + + let resolvers = ref [] + + let register_resolver + (type a) + (encoding : a encoding) + (resolver : R.context -> string -> a list Lwt.t) = + resolvers := Resolver { encoding ; resolver } :: !resolvers + + type context = R.context + + let partial_decode ?(alphabet=Alphabet.default) request len = + let zero = alphabet.encode.[0] in + let last = alphabet.encode.[base-1] in + let n = String.length request in + let min = raw_decode ~alphabet (request ^ String.make (len - n) zero) in + let max = raw_decode ~alphabet (request ^ String.make (len - n) last) in + let prefix_len = Utils.common_prefix min max in + String.sub min 0 prefix_len + + let complete ?alphabet context request = + let rec find s = function + | [] -> Lwt.return_nil + | Resolver { encoding ; resolver } :: resolvers -> + if not (has_prefix ~prefix:encoding.encoded_prefix s) then + find s resolvers + else + let prefix = + partial_decode ?alphabet request encoding.encoded_length in + let len = String.length prefix in + let ignored = String.length encoding.prefix in + if len <= ignored then + Lwt.return_nil + else begin + assert (String.sub prefix 0 ignored = encoding.prefix) ; + let msg = String.sub prefix ignored (len - ignored) in + resolver context msg >|= fun msgs -> + filter_map + (fun msg -> + let res = simple_encode encoding ?alphabet msg in + Utils.remove_prefix ~prefix:request res |> + Utils.map_option ~f:(fun _ -> res)) + msgs + end in + find request !resolvers + +end + +include MakeEncodings(struct let encodings = [] end) +include MakeResolvers(struct + type context = unit + let encodings = encodings + end) + +let register_resolver enc f = register_resolver enc (fun () s -> f s) +let complete ?alphabet s = complete ?alphabet () s + +module Make(C: sig type context end) = struct + include MakeEncodings(struct let encodings = !encodings end) + include MakeResolvers(struct + type context = C.context + let encodings = encodings + end) +end + +module Prefix = struct + + (* 32 *) + let block_hash = "\001\052" (* B(51) *) + let operation_hash = "\005\116" (* o(51) *) + let protocol_hash = "\002\170" (* P(51) *) + + (* 20 *) + let ed25519_public_key_hash = "\006\161\159" (* tz1(36) *) + + (* 16 *) + let cryptobox_public_key_hash = "\153\103" (* id(30) *) + + (* 32 *) + let ed25519_public_key = "\013\015\037\217" (* edpk(54) *) + + (* 64 *) + let ed25519_secret_key = "\043\246\078\007" (* edsk(98) *) + let ed25519_signature = "\009\245\205\134\018" (* edsig(99) *) + +end diff --git a/src/utils/base48.mli b/src/utils/base58.mli similarity index 59% rename from src/utils/base48.mli rename to src/utils/base58.mli index 802781391..51637b445 100644 --- a/src/utils/base48.mli +++ b/src/utils/base58.mli @@ -7,51 +7,18 @@ (* *) (**************************************************************************) -(** {1 Prefixed Base48Check encodings} *) +(** {1 Prefixed Base58Check encodings} *) -(** Like Bitcoin's Base58Check, all the data encoded in Tezos are - prefixed with a constant which depends on the kind of encoded - data. - - The [Prefix] exports all the prefix used by the Tezos Shell. Each - version of the economical protocol might complete this list. - - Unlike Bitcoin's Base58Check, the prefix in the unencoded-data - is visible in the encoded data. - -*) module Prefix : sig val block_hash: string - (** Prefix for block hashes: "\000". - (in Base48: "e" "f" or "g") *) - val operation_hash: string - (** Prefix for operation hashes: "\001". - (in Base48: "E" "F" or "G") *) - val protocol_hash: string - (** Prefix for protocol-version hashes: "\002". - (in Base48: "2" "3" or "4") *) - val ed25519_public_key_hash: string - (** Prefix for Ed25519 public key hashes: "\003". *) - val cryptobox_public_key_hash: string - (** Prefix for Ed25519 public key hashes: "\004". *) - val ed25519_public_key: string - (** Prefix for Ed25519 public key: "\012". *) - val ed25519_secret_key: string - (** Prefix for Ed25519 secret key: "\013". *) - val ed25519_signature: string - (** Prefix for Ed25519 signature key: "\014". *) - - val protocol_prefix: string - (** Prefix for all the encodings defined by economical protocol: - "\015". *) end @@ -63,7 +30,10 @@ type data = .. (** Abstract representation of registred encodings. The type paramater is the type of the encoded data, for instance [Hash.Block_hash.t]. *) type 'a encoding = private { - prefix: string; + prefix: string ; + length: int ; + encoded_prefix: string ; + encoded_length: int ; to_raw: 'a -> string ; of_raw: string -> 'a option ; wrap: 'a -> data ; @@ -77,33 +47,44 @@ type 'a encoding = private { the generic function [decode]). *) val register_encoding: prefix: string -> + length: int -> to_raw: ('a -> string) -> of_raw: (string -> 'a option) -> wrap: ('a -> data) -> 'a encoding +val check_encoded_prefix: 'a encoding -> string -> int -> unit + +module Alphabet : sig + type t + val bitcoin: t + val ripple: t + val flickr: t + val make: string -> t +end + (** Encoder for a given kind of data. *) -val simple_encode: ?alphabet:string -> 'a encoding -> 'a -> string +val simple_encode: ?alphabet:Alphabet.t -> 'a encoding -> 'a -> string (** Decoder for a given kind of data. It returns [None] when the decoded data does not start with the expected prefix. *) -val simple_decode: ?alphabet:string -> 'a encoding -> string -> 'a option +val simple_decode: ?alphabet:Alphabet.t -> 'a encoding -> string -> 'a option (** Generic decoder. It returns [None] when the decoded data does not start with a registred prefix. *) -val decode: ?alphabet:string -> string -> data option +val decode: ?alphabet:Alphabet.t -> string -> data option -(** {2 Completion of partial Base48Check value} *) +(** {2 Completion of partial Base58Check value} *) (** Register a (global) resolver for a previsously registred kind af data. *) val register_resolver: 'a encoding -> (string -> 'a list Lwt.t) -> unit -(** Try to complete a prefix of a Base48Check encoded data, by using +(** Try to complete a prefix of a Base58Check encoded data, by using the previously registered resolver associated to this kind of - data. Note that a prefix of [n] characters of a Base48-encoded + data. Note that a prefix of [n] characters of a Base58-encoded value provides at least [n/2] bytes of a prefix of the original value. *) -val complete: ?alphabet:string -> string -> string list Lwt.t +val complete: ?alphabet:Alphabet.t -> string -> string list Lwt.t (** {1 Low-level: distinct registering function for economical protocol} *) @@ -113,28 +94,33 @@ module Make(C: sig type context end) : sig val register_encoding: prefix: string -> + length: int -> to_raw: ('a -> string) -> of_raw: (string -> 'a option) -> wrap: ('a -> data) -> 'a encoding - val decode: ?alphabet:string -> string -> data option + val decode: ?alphabet:Alphabet.t -> string -> data option val register_resolver: 'a encoding -> (C.context -> string -> 'a list Lwt.t) -> unit val complete: - ?alphabet:string -> C.context -> string -> string list Lwt.t + ?alphabet:Alphabet.t -> C.context -> string -> string list Lwt.t end -(** {2 Low-level Base48Check encodings} *) +(** {2 Low-level Base58Check encodings} *) -(** Base48Check-encoding/decoding functions (with error detections). *) -val safe_encode: ?alphabet:string -> string -> string -val safe_decode: ?alphabet:string -> string -> string +(** Base58Check-encoding/decoding functions (with error detections). *) +val safe_encode: ?alphabet:Alphabet.t -> string -> string +val safe_decode: ?alphabet:Alphabet.t -> string -> string -(** Base48-encoding/decoding functions (without error detections). *) -val raw_encode: ?alphabet:string -> string -> string -val raw_decode: ?alphabet:string -> string -> string +(** Base58-encoding/decoding functions (without error detections). *) +val raw_encode: ?alphabet:Alphabet.t -> string -> string +val raw_decode: ?alphabet:Alphabet.t -> string -> string +(**/**) + +val partial_decode: ?alphabet:Alphabet.t -> string -> int -> string +val make_encoded_prefix: string -> int -> string * int diff --git a/src/utils/crypto_box.ml b/src/utils/crypto_box.ml index d3d1d4a0a..91a0fe8bf 100644 --- a/src/utils/crypto_box.ml +++ b/src/utils/crypto_box.ml @@ -18,13 +18,16 @@ type nonce = Sodium.Box.nonce type target = Z.t exception TargetNot256Bit -module Public_key_hash = Hash.Make_Blake2B (Base48) (struct +module Public_key_hash = Hash.Make_Blake2B (Base58) (struct let name = "Crypto_box.Public_key_hash" let title = "A Cryptobox public key ID" - let b48check_prefix = Base48.Prefix.cryptobox_public_key_hash + let b58check_prefix = Base58.Prefix.cryptobox_public_key_hash let size = Some 16 end) +let () = + Base58.check_encoded_prefix Public_key_hash.b58check_encoding "id" 30 + let hash pk = Public_key_hash.hash_bytes [Sodium.Box.Bigbytes.of_public_key pk] diff --git a/src/utils/hash.ml b/src/utils/hash.ml index 1e2bc1fce..ac847871f 100644 --- a/src/utils/hash.ml +++ b/src/utils/hash.ml @@ -57,14 +57,14 @@ module type HASH = sig include MINIMAL_HASH - val of_b48check: string -> t - val to_b48check: t -> string - val to_short_b48check: t -> string + val of_b58check: string -> t + val to_b58check: t -> string + val to_short_b58check: t -> string val encoding: t Data_encoding.t val pp: Format.formatter -> t -> unit val pp_short: Format.formatter -> t -> unit - type Base48.data += Hash of t - val b48check_encoding: t Base48.encoding + type Base58.data += Hash of t + val b58check_encoding: t Base58.encoding end @@ -76,7 +76,7 @@ end module type PrefixedName = sig include Name - val b48check_prefix: string + val b58check_prefix: string end (*-- Type specific Hash builder ---------------------------------------------*) @@ -188,31 +188,34 @@ end module Make_Blake2B (R : sig val register_encoding: prefix: string -> + length:int -> to_raw: ('a -> string) -> of_raw: (string -> 'a option) -> - wrap: ('a -> Base48.data) -> - 'a Base48.encoding + wrap: ('a -> Base58.data) -> + 'a Base58.encoding end) (K : PrefixedName) = struct include Make_minimal_Blake2B(K) (* Serializers *) - type Base48.data += Hash of t + type Base58.data += Hash of t - let b48check_encoding = + let b58check_encoding = R.register_encoding - ~prefix: K.b48check_prefix + ~prefix: K.b58check_prefix + ~length:size ~wrap: (fun s -> Hash s) ~of_raw:(fun h -> Some (of_string h)) ~to_raw:to_string - let of_b48check s = - match Base48.simple_decode b48check_encoding s with + let of_b58check s = + match Base58.simple_decode b58check_encoding s with | Some x -> x | None -> Format.kasprintf failwith "Unexpected hash (%s)" K.name - let to_b48check s = Base48.simple_encode b48check_encoding s + let to_b58check s = Base58.simple_encode b58check_encoding s - let to_short_b48check s = String.sub (to_b48check s) 0 12 + let to_short_b58check s = + String.sub (to_b58check s) 0 (10 + 2 * String.length K.b58check_prefix) let encoding = let open Data_encoding in @@ -220,17 +223,17 @@ module Make_Blake2B (R : sig ~binary: (conv to_bytes of_bytes (Fixed.bytes size)) ~json: - (describe ~title: (K.title ^ " (Base48Check-encoded Sha256)") @@ - conv to_b48check (Data_encoding.Json.wrap_error of_b48check) string) + (describe ~title: (K.title ^ " (Base58Check-encoded Sha256)") @@ + conv to_b58check (Data_encoding.Json.wrap_error of_b58check) string) let param ?(name=K.name) ?(desc=K.title) t = - Cli_entries.param ~name ~desc (fun _ str -> Lwt.return (of_b48check str)) t + Cli_entries.param ~name ~desc (fun _ str -> Lwt.return (of_b58check str)) t let pp ppf t = - Format.pp_print_string ppf (to_b48check t) + Format.pp_print_string ppf (to_b58check t) let pp_short ppf t = - Format.pp_print_string ppf (to_short_b48check t) + Format.pp_print_string ppf (to_short_b58check t) end @@ -268,10 +271,10 @@ module Hash_table (Hash : MINIMAL_HASH) (*-- Pre-instanciated hashes ------------------------------------------------*) module Block_hash = - Make_Blake2B (Base48) (struct + Make_Blake2B (Base58) (struct let name = "Block_hash" let title = "A Tezos block ID" - let b48check_prefix = Base48.Prefix.block_hash + let b58check_prefix = Base58.Prefix.block_hash let size = None end) @@ -280,10 +283,10 @@ module Block_hash_map = Hash_map (Block_hash) module Block_hash_table = Hash_table (Block_hash) module Operation_hash = - Make_Blake2B (Base48) (struct + Make_Blake2B (Base58) (struct let name = "Operation_hash" let title = "A Tezos operation ID" - let b48check_prefix = Base48.Prefix.operation_hash + let b58check_prefix = Base58.Prefix.operation_hash let size = None end) @@ -292,10 +295,10 @@ module Operation_hash_map = Hash_map (Operation_hash) module Operation_hash_table = Hash_table (Operation_hash) module Protocol_hash = - Make_Blake2B (Base48) (struct + Make_Blake2B (Base58) (struct let name = "Protocol_hash" let title = "A Tezos protocol ID" - let b48check_prefix = Base48.Prefix.protocol_hash + let b58check_prefix = Base58.Prefix.protocol_hash let size = None end) @@ -310,3 +313,7 @@ module Generic_hash = let size = None end) +let () = + Base58.check_encoded_prefix Block_hash.b58check_encoding "B" 51 ; + Base58.check_encoded_prefix Operation_hash.b58check_encoding "o" 51 ; + Base58.check_encoded_prefix Protocol_hash.b58check_encoding "P" 51 diff --git a/src/utils/hash.mli b/src/utils/hash.mli index aab5d7301..62efd2e7a 100644 --- a/src/utils/hash.mli +++ b/src/utils/hash.mli @@ -49,14 +49,14 @@ module type HASH = sig include MINIMAL_HASH - val of_b48check: string -> t - val to_b48check: t -> string - val to_short_b48check: t -> string + val of_b58check: string -> t + val to_b58check: t -> string + val to_short_b58check: t -> string val encoding: t Data_encoding.t val pp: Format.formatter -> t -> unit val pp_short: Format.formatter -> t -> unit - type Base48.data += Hash of t - val b48check_encoding: t Base48.encoding + type Base58.data += Hash of t + val b58check_encoding: t Base58.encoding end @@ -74,7 +74,7 @@ end module type PrefixedName = sig include Name - val b48check_prefix : string + val b58check_prefix : string end (** Builds a new Hash type using Sha256. *) @@ -83,10 +83,11 @@ module Make_Blake2B (Register : sig val register_encoding: prefix: string -> + length: int -> to_raw: ('a -> string) -> of_raw: (string -> 'a option) -> - wrap: ('a -> Base48.data) -> - 'a Base48.encoding + wrap: ('a -> Base58.data) -> + 'a Base58.encoding end) (Name : PrefixedName) : HASH diff --git a/test/Makefile b/test/Makefile index 734f8cd4b..c035cac0e 100644 --- a/test/Makefile +++ b/test/Makefile @@ -293,6 +293,12 @@ bisect: ##### +generate_hash: ../src/minutils/utils.cmx ../src/minutils/compare.cmx ../src/minutils/mBytes.cmx ../src/utils/base58.cmx ../src/minutils/hex_encode.cmx ../src/minutils/data_encoding.cmx ../src/utils/cli_entries.cmx ../src/utils/hash.cmx generate_hash.ml + ocamlfind ocamlopt -o $@ -linkpkg -package cstruct -package zarith -package ezjsonm -package sodium -package ocplib-json-typed.bson -package lwt.unix -package nocrypto -I ../src/utils/ -I ../src/minutils $^ + + +##### + lib/assert.cmx: lib/assert.cmi lib/assert.cmi: ../src/node/db/persist.cmi diff --git a/test/generate_hash.ml b/test/generate_hash.ml new file mode 100644 index 000000000..59b02413a --- /dev/null +++ b/test/generate_hash.ml @@ -0,0 +1,63 @@ + +open Base58 +open Hash +open Lwt.Infix + +type generator = + Generator : { + encoding: 'h encoding ; + generator: string -> 'h list ; + } -> generator + +let generators = ref [] + +let register_generator + (type a) + (encoding : a encoding) + (generator : string -> a list) = + generators := Generator { encoding ; generator } :: !generators + +let register (type t) (enc: t Base58.encoding) = + register_generator enc + (fun s -> + match + enc.of_raw + (s ^ + Sodium.Random.Bytes.generate (enc.length - String.length s)) with + | Some x -> [x] + | None -> []) + +let generate ?alphabet request = + let rec find s = function + | [] -> [] + | Generator { encoding ; generator } :: generators -> + if not (Utils.has_prefix ~prefix:encoding.encoded_prefix s) then + find s generators + else + let prefix = + partial_decode ?alphabet request encoding.encoded_length in + let len = String.length prefix in + let ignored = String.length encoding.prefix in + if len <= ignored then + [] + else begin + (* assert (String.sub prefix 0 ignored = encoding.prefix) ; *) + let msg = String.sub prefix ignored (len - ignored) in + let msgs = generator msg in + List.map + (fun msg -> simple_encode encoding ?alphabet msg) + msgs + end in + find request !generators + + +let () = + register Hash.Block_hash.b58check_encoding ; + register Hash.Protocol_hash.b58check_encoding ; + if not (!Sys.interactive) then begin + for i = 1 to Array.length Sys.argv - 1 do + List.iter + (Format.printf "%S@.") + (generate Sys.argv.(i)) + done + end diff --git a/test/lib/assert.ml b/test/lib/assert.ml index 707179f0f..d96f0bc5a 100644 --- a/test/lib/assert.ml +++ b/test/lib/assert.ml @@ -34,7 +34,7 @@ let equal_persist_list ?msg l1 l2 = let equal_block_hash_list ?msg l1 l2 = let msg = format_msg msg in - let pr_block_hash = Block_hash.to_short_b48check in + let pr_block_hash = Block_hash.to_short_b58check in Assert.make_equal_list ?msg Block_hash.equal pr_block_hash l1 l2 let equal_string_list ?msg l1 l2 = diff --git a/test/test_context.ml b/test/test_context.ml index 4225553a3..85aad5b95 100644 --- a/test/test_context.ml +++ b/test/test_context.ml @@ -17,12 +17,12 @@ let (//) = Filename.concat (** Basic blocks *) let genesis_block = - Block_hash.of_b48check - "eeeeeeeeeeeeeeefcF2dFpTjGjPAxRM3TqDrKkJf7DdkNHpX3DmaD" + Block_hash.of_b58check + "BLockGenesisGenesisGenesisGenesisGenesisGeneskvg68z" let genesis_protocol = - Protocol_hash.of_b48check - "2gagsSEvTKAHRjxAamgSdBNkv39VtNCqpaDXrrH4K8R4KQAAHrhe3" + Protocol_hash.of_b58check + "ProtoDemoDemoDemoDemoDemoDemoDemoDemoDemoDemoD3c8k9" let genesis_time = Time.of_seconds 0L diff --git a/test/test_state.ml b/test/test_state.ml index c23aab57d..33972f953 100644 --- a/test/test_state.ml +++ b/test/test_state.ml @@ -15,12 +15,12 @@ let (//) = Filename.concat (** Basic blocks *) let genesis_block = - Block_hash.of_b48check - "eeeeeeeeeeeeeeefcF2dFpTjGjPAxRM3TqDrKkJf7DdkNHpX3DmaD" + Block_hash.of_b58check + "BLockGenesisGenesisGenesisGenesisGenesisGeneskvg68z" let genesis_protocol = - Protocol_hash.of_b48check - "2gagsSEvTKAHRjxAamgSdBNkv39VtNCqpaDXrrH4K8R4KQAAHrhe3" + Protocol_hash.of_b58check + "ProtoDemoDemoDemoDemoDemoDemoDemoDemoDemoDemoD3c8k9" let genesis_time = Time.of_seconds 0L diff --git a/test/test_store.ml b/test/test_store.ml index 9caca4285..030628d34 100644 --- a/test/test_store.ml +++ b/test/test_store.ml @@ -17,12 +17,12 @@ let (//) = Filename.concat (** Basic blocks *) let genesis_block = - Block_hash.of_b48check - "eeeeeeeeeeeeeeefcF2dFpTjGjPAxRM3TqDrKkJf7DdkNHpX3DmaD" + Block_hash.of_b58check + "BLockGenesisGenesisGenesisGenesisGenesisGeneskvg68z" let genesis_protocol = - Protocol_hash.of_b48check - "2gagsSEvTKAHRjxAamgSdBNkv39VtNCqpaDXrrH4K8R4KQAAHrhe3" + Protocol_hash.of_b58check + "ProtoDemoDemoDemoDemoDemoDemoDemoDemoDemoDemoD3c8k9" let genesis_time = Time.of_seconds 0L @@ -121,12 +121,13 @@ let test_expand (s: Store.store) = Block.full_set s bh2 b2 >>= fun () -> Block.full_set s bh3 b3 >>= fun () -> Block.full_set s bh3' b3 >>= fun () -> - Base48.complete (Block_hash.to_short_b48check bh1) >>= fun res -> - Assert.equal_string_list ~msg:__LOC__ res [Block_hash.to_b48check bh1] ; - Base48.complete (Block_hash.to_short_b48check bh2) >>= fun res -> - Assert.equal_string_list ~msg:__LOC__ res [Block_hash.to_b48check bh2] ; - Base48.complete (Block_hash.to_short_b48check bh3) >>= fun res -> - Assert.equal_string_list ~msg:__LOC__ res [Block_hash.to_b48check bh3] ; + Base58.complete (Block_hash.to_short_b58check bh1) >>= fun res -> + Assert.equal_string_list ~msg:__LOC__ res [Block_hash.to_b58check bh1] ; + Base58.complete (Block_hash.to_short_b58check bh2) >>= fun res -> + Assert.equal_string_list ~msg:__LOC__ res [Block_hash.to_b58check bh2] ; + Base58.complete (Block_hash.to_short_b58check bh3) >>= fun res -> + Assert.equal_string_list ~msg:__LOC__ res + [Block_hash.to_b58check bh3' ; Block_hash.to_b58check bh3] ; Lwt.return_unit)