Client: don't try to generate vanity keys with wrong first letter

This commit is contained in:
Fabrice Le Fessant 2018-06-20 16:46:32 +02:00 committed by Benjamin Canou
parent 7e4a0f3368
commit 89c018f31b

View File

@ -38,62 +38,84 @@ let gen_keys_containing
~containing ~name (cctxt : #Client_context.io_wallet) = ~containing ~name (cctxt : #Client_context.io_wallet) =
let unrepresentable = let unrepresentable =
List.filter (fun s -> not @@ Base58.Alphabet.all_in_alphabet Base58.Alphabet.bitcoin s) containing in List.filter (fun s -> not @@ Base58.Alphabet.all_in_alphabet Base58.Alphabet.bitcoin s) containing in
let good_initial_char = "KLMNPQRSTUVWXYZabcdefghi" in
let bad_initial_char = "123456789ABCDEFGHJjkmnopqrstuvwxyz" in
match unrepresentable with match unrepresentable with
| _ :: _ -> | _ :: _ ->
cctxt#warning cctxt#error
"The following can't be written in the key alphabet (%a): %a" "@[<v 0>The following words can't be written in the key alphabet: %a.@,\
Base58.Alphabet.pp Base58.Alphabet.bitcoin Valid characters: %a@,\
Extra restriction for the first character: %s@]"
(Format.pp_print_list (Format.pp_print_list
~pp_sep:(fun ppf () -> Format.fprintf ppf ", ") ~pp_sep:(fun ppf () -> Format.fprintf ppf ", ")
(fun ppf s -> Format.fprintf ppf "'%s'" s)) (fun ppf s -> Format.fprintf ppf "'%s'" s))
unrepresentable >>= return unrepresentable
Base58.Alphabet.pp Base58.Alphabet.bitcoin
good_initial_char
| [] -> | [] ->
Public_key_hash.mem cctxt name >>=? fun name_exists -> let unrepresentable =
if name_exists && not force List.filter (fun s -> prefix &&
then String.contains bad_initial_char s.[0]) containing in
cctxt#warning match unrepresentable with
"Key for name '%s' already exists. Use --force to update." name >>= return | _ :: _ ->
else cctxt#error
begin "@[<v 0>The following words don't respect the first character restriction: %a.@,\
cctxt#warning "This process uses a brute force search and \ Valid characters: %a@,\
may take a long time to find a key." >>= fun () -> Extra restriction for the first character: %s@]"
let matches = (Format.pp_print_list
if prefix then ~pp_sep:(fun ppf () -> Format.fprintf ppf ", ")
let containing_tz1 = List.map ((^) "tz1") containing in (fun ppf s -> Format.fprintf ppf "'%s'" s))
(fun key -> List.exists unrepresentable
(fun containing -> Base58.Alphabet.pp Base58.Alphabet.bitcoin
String.sub key 0 (String.length containing) = containing) good_initial_char
containing_tz1) | [] ->
else Public_key_hash.mem cctxt name >>=? fun name_exists ->
let re = Re.Str.regexp (String.concat "\\|" containing) in if name_exists && not force
(fun key -> try ignore (Re.Str.search_forward re key 0); true then
with Not_found -> false) in cctxt#warning
let rec loop attempts = "Key for name '%s' already exists. Use --force to update." name >>= return
let public_key_hash, public_key, secret_key = else
Signature.generate_key () in begin
let hash = Signature.Public_key_hash.to_b58check @@ cctxt#warning "This process uses a brute force search and \
Signature.Public_key.hash public_key in may take a long time to find a key." >>= fun () ->
if matches hash let matches =
then if prefix then
let pk_uri = Tezos_signer_backends.Unencrypted.make_pk public_key in let containing_tz1 = List.map ((^) "tz1") containing in
begin (fun key -> List.exists
if encrypted then (fun containing ->
Tezos_signer_backends.Encrypted.encrypt cctxt secret_key String.sub key 0 (String.length containing) = containing)
containing_tz1)
else else
return (Tezos_signer_backends.Unencrypted.make_sk secret_key) let re = Re.Str.regexp (String.concat "\\|" containing) in
end >>=? fun sk_uri -> (fun key -> try ignore (Re.Str.search_forward re key 0); true
register_key cctxt ~force with Not_found -> false) in
(public_key_hash, pk_uri, sk_uri) name >>=? fun () -> let rec loop attempts =
return hash let public_key_hash, public_key, secret_key =
else begin if attempts mod 25_000 = 0 Signature.generate_key () in
then cctxt#message "Tried %d keys without finding a match" attempts let hash = Signature.Public_key_hash.to_b58check @@
else Lwt.return () end >>= fun () -> Signature.Public_key.hash public_key in
loop (attempts + 1) in if matches hash
loop 1 >>=? fun key_hash -> then
cctxt#message let pk_uri = Tezos_signer_backends.Unencrypted.make_pk public_key in
"Generated '%s' under the name '%s'." key_hash name >>= fun () -> begin
return () if encrypted then
end Tezos_signer_backends.Encrypted.encrypt cctxt secret_key
else
return (Tezos_signer_backends.Unencrypted.make_sk secret_key)
end >>=? fun sk_uri ->
register_key cctxt ~force
(public_key_hash, pk_uri, sk_uri) name >>=? fun () ->
return hash
else begin if attempts mod 25_000 = 0
then
cctxt#message "Tried %d keys without finding a match" attempts
else Lwt.return () end >>= fun () ->
loop (attempts + 1) in
loop 1 >>=? fun key_hash ->
cctxt#message
"Generated '%s' under the name '%s'." key_hash name >>= fun () ->
return ()
end
let commands () : Client_context.io_wallet Clic.command list = let commands () : Client_context.io_wallet Clic.command list =
let open Clic in let open Clic in