Client: simplify Client_keys.SIGNER

We now use `Uri.t` to represent public and secret keys. The 'remote'
scheme is replaced by `https://`, `unix:///` and `tcp://`.
This commit is contained in:
Grégoire Henry 2018-05-26 13:22:47 +02:00
parent 80dd9ebf24
commit f69d4a5186
26 changed files with 662 additions and 781 deletions

View File

@ -190,35 +190,35 @@ log_endorser() {
BOOTSTRAP1_IDENTITY="tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"
BOOTSTRAP1_PUBLIC="edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav"
BOOTSTRAP1_SECRET="edsk3gUfUPyBSfrS9CCgmCiQsTCHGkviBDusMxDJstFtojtc1zcpsh"
BOOTSTRAP1_SECRET="unencrypted:edsk3gUfUPyBSfrS9CCgmCiQsTCHGkviBDusMxDJstFtojtc1zcpsh"
BOOTSTRAP2_IDENTITY="tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN"
BOOTSTRAP2_PUBLIC="edpktzNbDAUjUk697W7gYg2CRuBQjyPxbEg8dLccYYwKSKvkPvjtV9"
BOOTSTRAP2_SECRET="edsk39qAm1fiMjgmPkw1EgQYkMzkJezLNewd7PLNHTkr6w9XA2zdfo"
BOOTSTRAP2_SECRET="unencrypted:edsk39qAm1fiMjgmPkw1EgQYkMzkJezLNewd7PLNHTkr6w9XA2zdfo"
BOOTSTRAP3_IDENTITY="tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU"
BOOTSTRAP3_PUBLIC="edpkuTXkJDGcFd5nh6VvMz8phXxU3Bi7h6hqgywNFi1vZTfQNnS1RV"
BOOTSTRAP3_SECRET="edsk4ArLQgBTLWG5FJmnGnT689VKoqhXwmDPBuGx3z4cvwU9MmrPZZ"
BOOTSTRAP3_SECRET="unencrypted:edsk4ArLQgBTLWG5FJmnGnT689VKoqhXwmDPBuGx3z4cvwU9MmrPZZ"
BOOTSTRAP4_IDENTITY="tz1b7tUupMgCNw2cCLpKTkSD1NZzB5TkP2sv"
BOOTSTRAP4_PUBLIC="edpkuFrRoDSEbJYgxRtLx2ps82UdaYc1WwfS9sE11yhauZt5DgCHbU"
BOOTSTRAP4_SECRET="edsk2uqQB9AY4FvioK2YMdfmyMrer5R8mGFyuaLLFfSRo8EoyNdht3"
BOOTSTRAP4_SECRET="unencrypted:edsk2uqQB9AY4FvioK2YMdfmyMrer5R8mGFyuaLLFfSRo8EoyNdht3"
BOOTSTRAP5_IDENTITY="tz1ddb9NMYHZi5UzPdzTZMYQQZoMub195zgv"
BOOTSTRAP5_PUBLIC="edpkv8EUUH68jmo3f7Um5PezmfGrRF24gnfLpH3sVNwJnV5bVCxL2n"
BOOTSTRAP5_SECRET="edsk4QLrcijEffxV31gGdN2HU7UpyJjA8drFoNcmnB28n89YjPNRFm"
BOOTSTRAP5_SECRET="unencrypted:edsk4QLrcijEffxV31gGdN2HU7UpyJjA8drFoNcmnB28n89YjPNRFm"
DICTATOR_SECRET="edsk31vznjHSSpGExDMHYASz45VZqXN4DPxvsa4hAyY8dHM28cZzp6"
DICTATOR_SECRET="unencrypted:edsk31vznjHSSpGExDMHYASz45VZqXN4DPxvsa4hAyY8dHM28cZzp6"
add_sandboxed_bootstrap_identities() {
${client} import unencrypted secret key bootstrap1 ${BOOTSTRAP1_SECRET}
${client} import unencrypted secret key bootstrap2 ${BOOTSTRAP2_SECRET}
${client} import unencrypted secret key bootstrap3 ${BOOTSTRAP3_SECRET}
${client} import unencrypted secret key bootstrap4 ${BOOTSTRAP4_SECRET}
${client} import unencrypted secret key bootstrap5 ${BOOTSTRAP5_SECRET}
${client} import secret key bootstrap1 ${BOOTSTRAP1_SECRET}
${client} import secret key bootstrap2 ${BOOTSTRAP2_SECRET}
${client} import secret key bootstrap3 ${BOOTSTRAP3_SECRET}
${client} import secret key bootstrap4 ${BOOTSTRAP4_SECRET}
${client} import secret key bootstrap5 ${BOOTSTRAP5_SECRET}
${client} import unencrypted secret key dictator ${DICTATOR_SECRET}
${client} import secret key dictator ${DICTATOR_SECRET}
}

View File

@ -16,7 +16,7 @@ let sign (cctxt : #Client_context.wallet) pkh data =
(MBytes.get_uint8 data 0) >>= fun () ->
Client_keys.get_key cctxt pkh >>=? fun (name, _pkh, sk_uri) ->
log "Signing data for key %s" name >>= fun () ->
Client_keys.sign cctxt sk_uri data >>=? fun signature ->
Client_keys.sign sk_uri data >>=? fun signature ->
return signature
let public_key (cctxt : #Client_context.wallet) pkh =

View File

@ -163,7 +163,9 @@ let main () =
inherit Client_context_unix.unix_wallet ~base_dir
end in
Client_keys.register_signer
(module Tezos_signer_backends.Encrypted) ;
(module Tezos_signer_backends.Encrypted.Make(struct
let cctxt = new Client_context_unix.unix_prompter
end)) ;
Client_keys.register_signer
(module Tezos_signer_backends.Unencrypted) ;
let commands =

View File

@ -30,136 +30,63 @@ module Public_key_hash = Client_aliases.Alias (struct
let name = "public key hash"
end)
type location = string list
module type LOCATOR = sig
val name : string
type t
val create : scheme:string -> location:location -> t
val scheme : t -> string
val location : t -> location
val to_string : t -> string
val pp : Format.formatter -> t -> unit
end
type sk_uri = Sk_locator of { scheme : string ; location : location }
type pk_uri = Pk_locator of { scheme : string ; location : location }
module Sk_locator = struct
let name = "secret key"
type t = sk_uri
let create ~scheme ~location =
Sk_locator { scheme ; location }
let scheme (Sk_locator { scheme }) = scheme
let location (Sk_locator { location }) = location
let to_string (Sk_locator { scheme ; location }) =
String.concat "/" ((scheme ^ ":") :: List.map Uri.pct_encode location)
let pp ppf loc =
Format.pp_print_string ppf (to_string loc)
end
module Pk_locator = struct
let name = "public key"
type t = pk_uri
let create ~scheme ~location =
Pk_locator { scheme ; location }
let scheme (Pk_locator { scheme }) = scheme
let location (Pk_locator { location }) = location
let to_string (Pk_locator { scheme ; location }) =
String.concat "/" ((scheme ^ ":") :: List.map Uri.pct_encode location)
let pp ppf loc =
Format.pp_print_string ppf (to_string loc)
end
module type KEY = sig
type t
val to_b58check : t -> string
val of_b58check_exn : string -> t
end
module Locator (K : KEY) (L : LOCATOR) = struct
include L
let uri_encoding =
Data_encoding.(conv Uri.to_string Uri.of_string string)
let of_unencrypted k =
L.create ~scheme:"unencrypted"
~location:[K.to_b58check k]
let of_string s =
match String.index s ':' with
| exception Not_found ->
of_unencrypted (K.of_b58check_exn s)
| i ->
let len = String.length s in
let scheme = String.sub s 0 i in
let location =
String.sub s (i+1) (len-i-1) |>
String.split '/' |>
List.map Uri.pct_decode |>
List.filter ((<>) "") in
create ~scheme ~location
let of_source s = return (of_string s)
let to_source t = return (to_string t)
let encoding = Data_encoding.(conv to_string of_string string)
module Entity (Name : sig val name: string end) = struct
include Name
type t = Uri.t
let pp = Uri.pp_hum
let of_source s = return (Uri.of_string s)
let to_source t = return (Uri.to_string t)
let encoding = uri_encoding
end
module Secret_key_locator = Locator(Signature.Secret_key)(Sk_locator)
module Secret_key = Client_aliases.Alias (Secret_key_locator)
module Public_key_locator = Locator(Signature.Public_key)(Pk_locator)
module Public_key = Client_aliases.Alias (Public_key_locator)
type pk_uri = Uri.t
let make_pk_uri x = x
type sk_uri = Uri.t
let make_sk_uri x = x
module Secret_key =
Client_aliases.Alias (Entity(struct let name = "secret_key" end))
module Public_key =
Client_aliases.Alias (Entity(struct let name = "public_key" end))
module type SIGNER = sig
type secret_key
type public_key
val scheme : string
val title : string
val description : string
val init : #Client_context.io_wallet -> unit tzresult Lwt.t
val sk_locator_of_human_input : #Client_context.io_wallet -> string list -> sk_uri tzresult Lwt.t
val pk_locator_of_human_input : #Client_context.io_wallet -> string list -> pk_uri tzresult Lwt.t
val sk_of_locator : sk_uri -> secret_key tzresult Lwt.t
val pk_of_locator : pk_uri -> public_key tzresult Lwt.t
val sk_to_locator : secret_key -> sk_uri Lwt.t
val pk_to_locator : public_key -> pk_uri Lwt.t
val neuterize : secret_key -> public_key Lwt.t
val public_key : public_key -> Signature.Public_key.t tzresult Lwt.t
val public_key_hash : public_key -> Signature.Public_key_hash.t tzresult Lwt.t
val neuterize : sk_uri -> pk_uri tzresult Lwt.t
val public_key : pk_uri -> Signature.Public_key.t tzresult Lwt.t
val public_key_hash : pk_uri -> Signature.Public_key_hash.t tzresult Lwt.t
val sign :
?watermark: Signature.watermark ->
secret_key -> MBytes.t -> Signature.t tzresult Lwt.t
sk_uri -> MBytes.t -> Signature.t tzresult Lwt.t
end
let signers_table : (string, (module SIGNER) * bool) Hashtbl.t = Hashtbl.create 13
let signers_table : (string, (module SIGNER)) Hashtbl.t = Hashtbl.create 13
let register_signer signer =
let module Signer = (val signer : SIGNER) in
Hashtbl.replace signers_table Signer.scheme (signer, false)
Hashtbl.replace signers_table Signer.scheme signer
let find_signer_for_key cctxt ~scheme =
let find_signer_for_key ~scheme =
match Hashtbl.find signers_table scheme with
| exception Not_found ->
fail (Unregistered_key_scheme scheme)
| signer, false ->
let module Signer = (val signer : SIGNER) in
Signer.init cctxt >>=? fun () ->
Hashtbl.replace signers_table scheme (signer, true) ;
return signer
| signer, true -> return signer
| signer -> return signer
let registered_signers () : (string * (module SIGNER)) list =
Hashtbl.fold (fun k (v, _) acc -> (k, v) :: acc) signers_table []
Hashtbl.fold (fun k v acc -> (k, v) :: acc) signers_table []
type error += Signature_mismatch of Secret_key_locator.t
type error += Signature_mismatch of sk_uri
let () =
register_error_kind `Permanent
@ -170,134 +97,87 @@ let () =
(fun ppf sk ->
Format.fprintf ppf
"The signer for %a produced an invalid signature"
Secret_key_locator.pp sk)
Data_encoding.(obj1 (req "locator" Secret_key_locator.encoding))
Uri.pp_hum sk)
Data_encoding.(obj1 (req "locator" uri_encoding))
(function Signature_mismatch sk -> Some sk | _ -> None)
(fun sk -> Signature_mismatch sk)
let sign ?watermark cctxt ((Sk_locator { scheme }) as skloc) buf =
find_signer_for_key cctxt ~scheme >>=? fun signer ->
let neuterize sk_uri =
let scheme = Option.unopt ~default:"" (Uri.scheme sk_uri) in
find_signer_for_key ~scheme >>=? fun signer ->
let module Signer = (val signer : SIGNER) in
Signer.sk_of_locator skloc >>=? fun t ->
Signer.sign ?watermark t buf >>=? fun signature ->
Signer.neuterize t >>= fun pk ->
Signer.public_key pk >>=? fun pubkey ->
Signer.neuterize sk_uri
let public_key pk_uri =
let scheme = Option.unopt ~default:"" (Uri.scheme pk_uri) in
find_signer_for_key ~scheme >>=? fun signer ->
let module Signer = (val signer : SIGNER) in
Signer.public_key pk_uri
let public_key_hash pk_uri =
public_key pk_uri >>=? fun pk ->
return (Signature.Public_key.hash pk)
let sign ?watermark sk_uri buf =
let scheme = Option.unopt ~default:"" (Uri.scheme sk_uri) in
find_signer_for_key ~scheme >>=? fun signer ->
let module Signer = (val signer : SIGNER) in
Signer.sign ?watermark sk_uri buf >>=? fun signature ->
Signer.neuterize sk_uri >>=? fun pk_uri ->
public_key pk_uri >>=? fun pubkey ->
fail_unless
(Signature.check ?watermark pubkey signature buf)
(Signature_mismatch skloc) >>=? fun () ->
(Signature_mismatch sk_uri) >>=? fun () ->
return signature
let append ?watermark cctxt loc buf =
sign ?watermark cctxt loc buf >>|? fun signature ->
let append ?watermark loc buf =
sign ?watermark loc buf >>|? fun signature ->
Signature.concat buf signature
let register_key cctxt ?(force=false)
(public_key_hash, public_key, secret_key) name =
Secret_key.add ~force cctxt name
(Secret_key_locator.of_unencrypted secret_key) >>=? fun () ->
Public_key.add ~force cctxt name
(Public_key_locator.of_unencrypted public_key) >>=? fun () ->
Public_key_hash.add ~force
cctxt name public_key_hash >>=? fun () ->
let register_key cctxt ?(force=false) (public_key_hash, pk_uri, sk_uri) name =
Public_key.add ~force cctxt name pk_uri >>=? fun () ->
Secret_key.add ~force cctxt name sk_uri >>=? fun () ->
Public_key_hash.add ~force cctxt name public_key_hash >>=? fun () ->
return ()
let gen_keys ?(force=false) ?algo ?seed (cctxt : #Client_context.io_wallet) name =
let key = Signature.generate_key ?algo ?seed () in
register_key cctxt ~force key name
let gen_keys_containing ?(prefix=false) ?(force=false) ~containing ~name (cctxt : #Client_context.io_wallet) =
let unrepresentable =
List.filter (fun s -> not @@ Base58.Alphabet.all_in_alphabet Base58.Alphabet.bitcoin s) containing in
match unrepresentable with
| _ :: _ ->
cctxt#warning
"The following can't be written in the key alphabet (%a): %a"
Base58.Alphabet.pp Base58.Alphabet.bitcoin
(Format.pp_print_list
~pp_sep:(fun ppf () -> Format.fprintf ppf ", ")
(fun ppf s -> Format.fprintf ppf "'%s'" s))
unrepresentable >>= return
| [] ->
Public_key_hash.mem cctxt name >>=? fun name_exists ->
if name_exists && not force
then
cctxt#warning
"Key for name '%s' already exists. Use -force to update." name >>= return
else
begin
cctxt#warning "This process uses a brute force search and \
may take a long time to find a key." >>= fun () ->
let matches =
if prefix then
let containing_tz1 = List.map ((^) "tz1") containing in
(fun key -> List.exists
(fun containing ->
String.sub key 0 (String.length containing) = containing)
containing_tz1)
else
let re = Re.Str.regexp (String.concat "\\|" containing) in
(fun key -> try ignore (Re.Str.search_forward re key 0); true
with Not_found -> false) in
let rec loop attempts =
let public_key_hash, public_key, secret_key =
Signature.generate_key () in
let hash = Signature.Public_key_hash.to_b58check @@
Signature.Public_key.hash public_key in
if matches hash
then
Secret_key.add ~force cctxt name
(Secret_key_locator.of_unencrypted secret_key) >>=? fun () ->
Public_key.add ~force cctxt name
(Public_key_locator.of_unencrypted public_key) >>=? fun () ->
Public_key_hash.add ~force cctxt name public_key_hash >>=? 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 get_key (cctxt : #Client_context.wallet) pkh =
let raw_get_key (cctxt : #Client_context.wallet) pkh =
Public_key_hash.rev_find cctxt pkh >>=? function
| None -> failwith "no keys for the source contract manager"
| Some n ->
Public_key.find cctxt n >>=? fun pk ->
Secret_key.find cctxt n >>=? fun sk ->
let scheme = Secret_key_locator.scheme sk in
find_signer_for_key cctxt ~scheme >>=? fun signer ->
let module Signer = (val signer : SIGNER) in
Signer.pk_of_locator pk >>=? fun pk ->
Signer.public_key pk >>=? fun pk ->
return (n, pk, sk)
Public_key.find_opt cctxt n >>=? fun pk_uri ->
Secret_key.find_opt cctxt n >>=? fun sk_uri ->
begin
Option.unopt_map
~default:Lwt.return_none
~f:(fun pkh ->
public_key pkh >>= function
| Error e ->
Format.eprintf "PLOP: %a@." pp_print_error e ;
Lwt.return_none
| Ok pk -> Lwt.return_some pk)
pk_uri
end >>= fun pk ->
return (n, pk, sk_uri)
let get_public_key (cctxt : #Client_context.wallet) pkh =
Public_key_hash.rev_find cctxt pkh >>=? function
| None -> failwith "no keys for the source contract manager"
| Some n ->
Public_key.find cctxt n >>=? fun pk ->
let scheme = Public_key_locator.scheme pk in
find_signer_for_key cctxt ~scheme >>=? fun signer ->
let module Signer = (val signer : SIGNER) in
Signer.pk_of_locator pk >>=? fun pk ->
Signer.public_key pk >>=? fun pk ->
return (n, pk)
let get_key cctxt pkh =
raw_get_key cctxt pkh >>=? function
| (pkh, Some pk, Some sk) -> return (pkh, pk, sk)
| (_pkh, _pk, None) -> failwith "... FIXME ... E"
| (_pkh, None, _sk) -> failwith "... FIXME ... F"
let get_keys (wallet : #Client_context.io_wallet) =
Secret_key.load wallet >>=? fun sks ->
Lwt_list.filter_map_s begin fun (name, sk) ->
let get_public_key cctxt pkh =
raw_get_key cctxt pkh >>=? function
| (pkh, Some pk, _sk) -> return (pkh, pk)
| (_pkh, None, _sk) -> failwith "... FIXME ... G"
let get_keys (cctxt : #Client_context.wallet) =
Secret_key.load cctxt >>=? fun sks ->
Lwt_list.filter_map_s begin fun (name, sk_uri) ->
begin
Public_key.find wallet name >>=? fun pk ->
Public_key_hash.find wallet name >>=? fun pkh ->
let scheme = Public_key_locator.scheme pk in
find_signer_for_key wallet ~scheme >>=? fun signer ->
let module Signer = (val signer : SIGNER) in
Signer.pk_of_locator pk >>=? fun pk ->
Signer.public_key pk >>=? fun pk ->
return (name, pkh, pk, sk)
Public_key.find cctxt name >>=? fun pk_uri ->
Public_key_hash.find cctxt name >>=? fun pkh ->
public_key pk_uri >>=? fun pk ->
return (name, pkh, pk, sk_uri)
end >>= function
| Ok r -> Lwt.return (Some r)
| Error _ -> Lwt.return_none
@ -308,24 +188,18 @@ let list_keys cctxt =
Public_key_hash.load cctxt >>=? fun l ->
map_s
(fun (name, pkh) ->
Public_key.find_opt cctxt name >>=? fun pkm ->
Secret_key.find_opt cctxt name >>=? fun pks ->
return (name, pkh, pkm, pks))
raw_get_key cctxt pkh >>= function
| Ok (_name, pk, sk_uri) ->
return (name, pkh, pk, sk_uri)
| Error _ ->
return (name, pkh, None, None))
l
let alias_keys cctxt name =
Public_key_hash.load cctxt >>=? fun l ->
let rec find_key = function
| [] -> return None
| (key_name, pkh) :: tl ->
if key_name = name
then begin
Public_key.find_opt cctxt name >>=? fun pkm ->
Secret_key.find_opt cctxt name >>=? fun pks ->
return (Some (pkh, pkm, pks))
end
else find_key tl
in find_key l
Public_key_hash.find cctxt name >>=? fun pkh ->
raw_get_key cctxt pkh >>= function
| Ok (_name, pk, sk_uri) -> return (Some (pkh, pk, sk_uri))
| Error _ -> return None
let force_switch () =
Clic.switch

View File

@ -7,28 +7,11 @@
(* *)
(**************************************************************************)
(** {2 Location of keys using schemes} *)
type location = string list
type sk_uri = Sk_locator of { scheme : string ; location : location }
type pk_uri = Pk_locator of { scheme : string ; location : location }
module type LOCATOR = sig
val name : string
type t
val create : scheme:string -> location:location -> t
val scheme : t -> string
val location : t -> location
val to_string : t -> string
val pp : Format.formatter -> t -> unit
end
module Secret_key_locator : LOCATOR with type t = sk_uri
module Public_key_locator : LOCATOR with type t = pk_uri
(** {2 Cryptographic keys tables } *)
type pk_uri = private Uri.t
type sk_uri = private Uri.t
module Public_key_hash :
Client_aliases.Alias with type t = Signature.Public_key_hash.t
module Public_key :
@ -39,8 +22,6 @@ module Secret_key :
(** {2 Interface for external signing modules.} *)
module type SIGNER = sig
type secret_key
type public_key
val scheme : string
(** [scheme] is the name of the scheme implemented by this signer
@ -53,47 +34,18 @@ module type SIGNER = sig
(** [description] is a multi-line human readable description of the
signer, that should include the format of key specifications. *)
val init :
#Client_context.io_wallet -> unit tzresult Lwt.t
(** [init wallet] initialized the signer module (plugin
dependent). *)
val sk_locator_of_human_input :
#Client_context.io_wallet -> string list -> sk_uri tzresult Lwt.t
(** [sk_locator_of_human_input wallet spec] is the [sk_locator]
corresponding to the human readable specification [spec] (plugin
dependent). *)
val pk_locator_of_human_input :
#Client_context.io_wallet -> string list -> pk_uri tzresult Lwt.t
(** [pk_locator_of_human_input wallet spec] is the [pk_locator]
corresponding to the human readable specification [spec] (plugin
dependent). *)
val sk_of_locator : sk_uri -> secret_key tzresult Lwt.t
(** [sk_of_locator skloc] is the secret key at [skloc]. *)
val pk_of_locator : pk_uri -> public_key tzresult Lwt.t
(** [pk_of_locator pkloc] is the public key at [pkloc]. *)
val sk_to_locator : secret_key -> sk_uri Lwt.t
(** [sk_to_locator sk] is the location of secret key [sk]. *)
val pk_to_locator : public_key -> pk_uri Lwt.t
(** [pk_to_locator pk] is the location of public key [pk]. *)
val neuterize : secret_key -> public_key Lwt.t
val neuterize : sk_uri -> pk_uri tzresult Lwt.t
(** [neuterize sk] is the corresponding [pk]. *)
val public_key : public_key -> Signature.Public_key.t tzresult Lwt.t
val public_key : pk_uri -> Signature.Public_key.t tzresult Lwt.t
(** [public_key pk] is the Ed25519 version of [pk]. *)
val public_key_hash : public_key -> Signature.Public_key_hash.t tzresult Lwt.t
val public_key_hash : pk_uri -> Signature.Public_key_hash.t tzresult Lwt.t
(** [public_key_hash pk] is the hash of [pk]. *)
val sign :
?watermark: Signature.watermark ->
secret_key -> MBytes.t -> Signature.t tzresult Lwt.t
sk_uri -> MBytes.t -> Signature.t tzresult Lwt.t
(** [sign ?watermark sk data] is signature obtained by signing [data] with
[sk]. *)
end
@ -104,59 +56,51 @@ val register_signer : (module SIGNER) -> unit
val registered_signers : unit -> (string * (module SIGNER)) list
val find_signer_for_key :
#Client_context.io_wallet -> scheme:string -> (module SIGNER) tzresult Lwt.t
val public_key : pk_uri -> Signature.Public_key.t tzresult Lwt.t
val public_key_hash : pk_uri -> Signature.Public_key_hash.t tzresult Lwt.t
val neuterize : sk_uri -> pk_uri tzresult Lwt.t
val sign :
?watermark:Signature.watermark ->
#Client_context.io_wallet ->
sk_uri -> MBytes.t -> Signature.t tzresult Lwt.t
val append :
?watermark:Signature.watermark ->
#Client_context.io_wallet ->
sk_uri -> MBytes.t -> MBytes.t tzresult Lwt.t
val gen_keys :
?force:bool ->
?algo:Signature.algo ->
?seed:MBytes.t ->
#Client_context.io_wallet -> string -> unit tzresult Lwt.t
val register_key :
#Client_context.wallet ->
?force:bool ->
(Signature.Public_key_hash.t *
Signature.Public_key.t *
Signature.Secret_key.t) -> string -> unit tzresult Lwt.t
val gen_keys_containing :
?prefix:bool ->
?force:bool ->
containing:string list ->
name:string ->
#Client_context.io_wallet -> unit tzresult Lwt.t
(Signature.Public_key_hash.t * pk_uri * sk_uri) -> string -> unit tzresult Lwt.t
val list_keys :
#Client_context.wallet ->
(string * Public_key_hash.t * pk_uri option * sk_uri option) list tzresult Lwt.t
(string * Public_key_hash.t * Signature.public_key option * sk_uri option) list tzresult Lwt.t
val alias_keys :
#Client_context.wallet -> string ->
(Public_key_hash.t * pk_uri option * sk_uri option) option tzresult Lwt.t
(Public_key_hash.t * Signature.public_key option * sk_uri option) option tzresult Lwt.t
val get_key:
#Client_context.io_wallet ->
val get_key :
#Client_context.wallet ->
Public_key_hash.t ->
(string * Signature.Public_key.t * sk_uri) tzresult Lwt.t
val get_public_key:
#Client_context.io_wallet ->
val get_public_key :
#Client_context.wallet ->
Public_key_hash.t ->
(string * Signature.Public_key.t) tzresult Lwt.t
val get_keys:
#Client_context.io_wallet ->
#Client_context.wallet ->
(string * Public_key_hash.t * Signature.Public_key.t * sk_uri) list tzresult Lwt.t
val force_switch : unit -> (bool, 'ctx) Clic.arg
(**/**)
val make_pk_uri : Uri.t -> pk_uri
val make_sk_uri : Uri.t -> sk_uri

View File

@ -77,9 +77,15 @@ let main select_commands =
Client_keys.register_signer
(module Tezos_signer_backends.Unencrypted) ;
Client_keys.register_signer
(module Tezos_signer_backends.Encrypted) ;
(module Tezos_signer_backends.Encrypted.Make(struct
let cctxt = new Client_context_unix.unix_prompter
end)) ;
Client_keys.register_signer
(module Tezos_signer_backends.Remote) ;
(module Tezos_signer_backends.Https) ;
Client_keys.register_signer
(module Tezos_signer_backends.Socket.Unix) ;
Client_keys.register_signer
(module Tezos_signer_backends.Socket.Tcp) ;
Lwt.catch begin fun () -> begin
Client_config.parse_config_args
(new unix_full

View File

@ -22,7 +22,64 @@ let sig_algo_arg =
~default: "ed25519"
(Signature.algo_param ())
let commands () =
let gen_keys_containing
?(prefix=false) ?(force=false)
~containing ~name (cctxt : #Client_context.io_wallet) =
let unrepresentable =
List.filter (fun s -> not @@ Base58.Alphabet.all_in_alphabet Base58.Alphabet.bitcoin s) containing in
match unrepresentable with
| _ :: _ ->
cctxt#warning
"The following can't be written in the key alphabet (%a): %a"
Base58.Alphabet.pp Base58.Alphabet.bitcoin
(Format.pp_print_list
~pp_sep:(fun ppf () -> Format.fprintf ppf ", ")
(fun ppf s -> Format.fprintf ppf "'%s'" s))
unrepresentable >>= return
| [] ->
Public_key_hash.mem cctxt name >>=? fun name_exists ->
if name_exists && not force
then
cctxt#warning
"Key for name '%s' already exists. Use -force to update." name >>= return
else
begin
cctxt#warning "This process uses a brute force search and \
may take a long time to find a key." >>= fun () ->
let matches =
if prefix then
let containing_tz1 = List.map ((^) "tz1") containing in
(fun key -> List.exists
(fun containing ->
String.sub key 0 (String.length containing) = containing)
containing_tz1)
else
let re = Re.Str.regexp (String.concat "\\|" containing) in
(fun key -> try ignore (Re.Str.search_forward re key 0); true
with Not_found -> false) in
let rec loop attempts =
let public_key_hash, public_key, secret_key =
Signature.generate_key () in
let hash = Signature.Public_key_hash.to_b58check @@
Signature.Public_key.hash public_key in
if matches hash
then
let pk_uri = Tezos_signer_backends.Unencrypted.make_pk public_key in
let sk_uri = Tezos_signer_backends.Unencrypted.make_sk secret_key in
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 open Clic in
let show_private_switch =
switch
@ -61,7 +118,10 @@ let commands () =
@@ stop)
(fun (force, algo) name (cctxt : #Client_context.io_wallet) ->
Secret_key.of_fresh cctxt force name >>=? fun name ->
gen_keys ~force ~algo cctxt name) ;
let (pkh, pk, sk) = Signature.generate_key ~algo () in
let pk_uri = Tezos_signer_backends.Unencrypted.make_pk pk in
let sk_uri = Tezos_signer_backends.Unencrypted.make_sk sk in
register_key cctxt ~force (pkh, pk_uri, sk_uri) name) ;
command ~group ~desc: "Generate (unencrypted) keys including the given string."
(args2
@ -82,69 +142,53 @@ let commands () =
command ~group ~desc: "Add a secret key to the wallet."
(args1 (Secret_key.force_switch ()))
(prefix "import"
@@ string
~name:"scheme"
~desc:"signer to use for this secret key\n\
Use command `list signing schemes` for a list of \
supported signers."
@@ prefixes [ "secret" ; "key" ]
@@ Secret_key.fresh_alias_param
@@ seq_of_param
(string
~name:"spec"
~desc:"secret key specification\n\
Varies from one scheme to the other.\n\
Use command `list signing schemes` for more \
information."))
(fun force scheme name spec cctxt ->
@@ param
~name:"uri"
~desc:"secret key\n\
Varies from one scheme to the other.\n\
Use command `list signing schemes` for more \
information."
(parameter (fun _ s ->
try return (Client_keys.make_sk_uri @@ Uri.of_string s)
with Failure s -> failwith "Error while parsing uri: %s" s))
@@ stop)
(fun force name sk_uri (cctxt : Client_context.io_wallet) ->
Secret_key.of_fresh cctxt force name >>=? fun name ->
find_signer_for_key ~scheme cctxt >>=? fun signer ->
let module Signer = (val signer : SIGNER) in
Signer.sk_locator_of_human_input
(cctxt :> Client_context.io_wallet) spec >>=? fun skloc ->
Signer.sk_of_locator skloc >>=? fun sk ->
Signer.neuterize sk >>= fun pk ->
Signer.pk_to_locator pk >>= fun pkloc ->
Public_key.find_opt cctxt name >>=? function
| None ->
Signer.public_key_hash pk >>=? fun pkh ->
Secret_key.add ~force cctxt name skloc >>=? fun () ->
Public_key_hash.add ~force cctxt name pkh >>=? fun () ->
Public_key.add ~force cctxt name pkloc
| Some pk ->
fail_unless (pkloc = pk || force)
(failure
"public and secret keys '%s' don't correspond, \
please don't use -force" name) >>=? fun () ->
Secret_key.add ~force cctxt name skloc) ;
Client_keys.neuterize sk_uri >>=? fun pk_uri ->
begin
Public_key.find_opt cctxt name >>=? function
| None -> return ()
| Some pk ->
fail_unless (pk_uri = pk || force)
(failure
"public and secret keys '%s' don't correspond, \
please don't use -force" name)
end >>=? fun () ->
Client_keys.public_key_hash pk_uri >>=? fun pkh ->
register_key cctxt ~force (pkh, pk_uri, sk_uri) name) ;
command ~group ~desc: "Add a public key to the wallet."
(args1 (Public_key.force_switch ()))
(prefix "import"
@@ string
~name:"scheme"
~desc:"signer to use for this public key\n\
Use command `list signing schemes` for a list of \
supported signers."
@@ prefixes [ "public" ; "key" ]
@@ Public_key.fresh_alias_param
@@ seq_of_param
(string
~name:"spec"
~desc:"public key specification\n\
Varies from one scheme to the other.\n\
Use command `list signing schemes` for more \
information."))
(fun force scheme name location cctxt ->
@@ param
~name:"uri"
~desc:"public key\n\
Varies from one scheme to the other.\n\
Use command `list signing schemes` for more \
information."
(parameter (fun _ s ->
try return (Client_keys.make_pk_uri @@ Uri.of_string s)
with Failure s -> failwith "Error while parsing uri: %s" s))
@@ stop)
(fun force name pk_uri (cctxt : Client_context.io_wallet) ->
Public_key.of_fresh cctxt force name >>=? fun name ->
find_signer_for_key ~scheme cctxt >>=? fun signer ->
let module Signer = (val signer : SIGNER) in
Signer.pk_locator_of_human_input
(cctxt :> Client_context.io_wallet) location >>=? fun pkloc ->
Signer.pk_of_locator pkloc >>=? fun pk ->
Signer.public_key_hash pk >>=? fun pkh ->
Client_keys.public_key_hash pk_uri >>=? fun pkh ->
Public_key_hash.add ~force cctxt name pkh >>=? fun () ->
Public_key.add ~force cctxt name pkloc) ;
Public_key.add ~force cctxt name pk_uri) ;
command ~group ~desc: "Add an identity to the wallet."
(args1 (Public_key.force_switch ()))
@ -166,10 +210,13 @@ let commands () =
begin match pk, sk with
| None, None ->
cctxt#message "%s: %s" name v
| _, Some Sk_locator { scheme } ->
| _, Some uri ->
let scheme =
Option.unopt ~default:"unencrypted" @@
Uri.scheme (uri : sk_uri :> Uri.t) in
cctxt#message "%s: %s (%s sk known)" name v scheme
| Some Pk_locator { scheme }, _ ->
cctxt#message "%s: %s (%s pk known)" name v scheme
| Some _, _ ->
cctxt#message "%s: %s (pk known)" name v
end >>= fun () -> return ()
end l) ;
@ -179,36 +226,35 @@ let commands () =
@@ Public_key_hash.alias_param
@@ stop)
(fun show_private (name, _) (cctxt : #Client_context.io_wallet) ->
let ok_lwt x = x >>= (fun x -> return x) in
alias_keys cctxt name >>=? fun key_info ->
match key_info with
| None -> ok_lwt @@ cctxt#message "No keys found for identity"
| None ->
cctxt#message "No keys found for identity" >>= fun () ->
return ()
| Some (pkh, pk, skloc) ->
ok_lwt @@ cctxt#message "Hash: %a"
Signature.Public_key_hash.pp pkh >>=? fun () ->
cctxt#message "Hash: %a"
Signature.Public_key_hash.pp pkh >>= fun () ->
match pk with
| None -> return ()
| Some (Pk_locator { scheme } as pkloc) ->
find_signer_for_key ~scheme cctxt >>=? fun signer ->
let module Signer = (val signer : SIGNER) in
Signer.pk_of_locator pkloc >>=? fun pk ->
Signer.public_key pk >>=? fun pk ->
ok_lwt @@ cctxt#message "Public Key: %a"
Signature.Public_key.pp pk >>=? fun () ->
| Some pk ->
cctxt#message "Public Key: %a"
Signature.Public_key.pp pk >>= fun () ->
if show_private then
match skloc with
| None -> return ()
| Some skloc ->
Secret_key.to_source skloc >>=? fun skloc ->
ok_lwt @@ cctxt#message "Secret Key: %s" skloc
else return ()) ;
cctxt#message "Secret Key: %s" skloc >>= fun () ->
return ()
else
return ()) ;
command ~group ~desc: "Forget the entire wallet of keys."
(args1 (Clic.switch
~long:"force" ~short:'f'
~doc:"you got to use the force for that" ()))
(fixed [ "forget" ; "all" ; "keys" ])
(fun force cctxt ->
(fun force (cctxt : Client_context.io_wallet) ->
fail_unless force
(failure "this can only used with option -force") >>=? fun () ->
Public_key.set cctxt [] >>=? fun () ->

View File

@ -6,7 +6,8 @@
(libraries (tezos-base
tezos-client-base
tezos-rpc
tezos-shell-services))
tezos-shell-services
tezos-signer-backends))
(library_flags (:standard -linkall))
(flags (:standard -w -9+27-30-32-40@8
-safe-string

View File

@ -11,153 +11,156 @@ open Client_keys
let scheme = "encrypted"
let title =
"Built-in signer using encrypted keys."
module Raw = struct
let description =
"If you try to import a secret key without additional argument, you will \
be asked to either generate a new key, or to import the elements \
from your fundraiser paper wallet.\n\
If you add an argument when importing a secret key, \
the format is the raw Base58-encoded key (starting with 'edsk').\n\
The format for importing public keys is the raw Base58-encoded \
key (starting with 'edpk')."
(* https://tools.ietf.org/html/rfc2898#section-4.1 *)
let salt_len = 8
type secret_key = Signature.Secret_key.t
type public_key = Signature.Public_key.t
(* Fixed zero nonce *)
let nonce = Crypto_box.zero_nonce
(* https://tools.ietf.org/html/rfc2898#section-4.1 *)
let salt_len = 8
let pbkdf ~salt ~password =
Cstruct.to_bigarray
(Pbkdf.pbkdf2 ~prf:`SHA512 ~count:2048 ~dk_len:32l
~salt: (Cstruct.of_bigarray salt)
~password: (Cstruct.of_bigarray password))
(* Fixed zero nonce *)
let nonce = Crypto_box.zero_nonce
let encrypt ~password sk =
let salt = Rand.generate salt_len in
let key = Crypto_box.Secretbox.unsafe_of_bytes (pbkdf ~password ~salt) in
let msg = Data_encoding.Binary.to_bytes_exn Signature.Secret_key.encoding sk in
let encrypted_passwd = Crypto_box.Secretbox.box key msg nonce in
MBytes.concat "" [ salt ; encrypted_passwd ]
(* skloc -> Signature.Secret_key.t *)
let decrypted_sks = Hashtbl.create 13
let decrypt ~password ~encrypted_sk =
let len = MBytes.length encrypted_sk in
let salt = MBytes.sub encrypted_sk 0 salt_len in
let encrypted_sk = MBytes.sub encrypted_sk salt_len (len - salt_len) in
let key = Crypto_box.Secretbox.unsafe_of_bytes (pbkdf ~salt ~password) in
match Crypto_box.Secretbox.box_open key encrypted_sk nonce with
| None -> return None
| Some bytes ->
match Data_encoding.Binary.of_bytes Signature.Secret_key.encoding bytes with
| None -> failwith "... FIXME ... D" (* corrupted data *)
| Some sk -> return (Some sk)
let pbkdf ~salt ~password =
let open Cstruct in
let salt = of_bigarray salt in
let password = of_bigarray password in
to_bigarray
(Pbkdf.pbkdf2 ~prf:`SHA512 ~count:2048 ~dk_len:32l ~salt ~password)
end
let rec decrypt_sk sk salt = function
| [] -> None
| password :: pws ->
let key = Crypto_box.Secretbox.unsafe_of_bytes (pbkdf ~password ~salt) in
match Crypto_box.Secretbox.box_open key sk nonce with
| None -> decrypt_sk sk salt pws
| Some sk -> Some sk
let decrypted = Hashtbl.create 13
let passwords = ref []
let salt_skenc_of_skloc skloc =
let open Cstruct in
let skloc = of_string skloc in
let len = len skloc in
let salt = sub skloc 0 salt_len in
let skenc = sub skloc salt_len (len - salt_len) in
to_bigarray salt, to_bigarray skenc
let rec interactive_decrypt_loop
(cctxt : #Client_context.prompter)
?name ~encrypted_sk =
begin
match name with
| None ->
cctxt#prompt_password
"Enter password for encrypted key: "
| Some name ->
cctxt#prompt_password
"Enter password for encrypted key \"%s\": " name
end >>=? fun password ->
Raw.decrypt ~password ~encrypted_sk >>=? function
| None ->
interactive_decrypt_loop cctxt ?name ~encrypted_sk
| Some sk ->
passwords := password :: !passwords ;
return sk
let rec passwd_ask_loop (cctxt : #Client_context.io_wallet) ~name ~salt ~skenc =
cctxt#prompt_password "Enter password for encrypted key %s: " name >>=? fun password ->
let key = pbkdf ~salt ~password in
let key = Crypto_box.Secretbox.unsafe_of_bytes key in
match Crypto_box.Secretbox.box_open key skenc nonce with
| None -> passwd_ask_loop cctxt ~name ~salt ~skenc
| Some decrypted_sk ->
return (password, (Data_encoding.Binary.of_bytes_exn
Signature.Secret_key.encoding
decrypted_sk))
let rec noninteractice_decrypt_loop ~encrypted_sk = function
| [] -> return None
| password :: passwords ->
Raw.decrypt ~password ~encrypted_sk >>=? function
| None -> noninteractice_decrypt_loop ~encrypted_sk passwords
| Some sk -> return (Some sk)
let ask_all_passwords (cctxt : #Client_context.io_wallet) sks =
fold_left_s begin fun a (name, skloc) ->
if Secret_key_locator.scheme skloc <> scheme then
return a
else
match Secret_key_locator.location skloc with
|location :: _ -> begin
match Base58.safe_decode location with
| None -> Lwt.fail Exit
| Some payload ->
let salt, skenc = salt_skenc_of_skloc payload in
match decrypt_sk skenc salt a with
| Some sk ->
Hashtbl.replace decrypted_sks location
(Data_encoding.Binary.of_bytes_exn Signature.Secret_key.encoding sk);
return a
| None ->
passwd_ask_loop
cctxt ~name ~salt ~skenc >>=? fun (passwd, decrypted_sk) ->
Hashtbl.replace decrypted_sks location decrypted_sk ;
return (passwd :: a)
end
|_ -> Lwt.fail Exit
end [] sks
let decrypt_payload cctxt ?name encrypted_sk =
match Base58.safe_decode encrypted_sk with
| None -> failwith "... FIXME ... A"
| Some encrypted_sk ->
let encrypted_sk = MBytes.of_string encrypted_sk in
noninteractice_decrypt_loop ~encrypted_sk !passwords >>=? function
| Some sk -> return sk
| None -> interactive_decrypt_loop cctxt ?name ~encrypted_sk
let init cctxt =
let decrypt cctxt ?name sk_uri =
let payload = Uri.path (sk_uri : sk_uri :> Uri.t) in
decrypt_payload cctxt ?name payload >>=? fun sk ->
Hashtbl.replace decrypted sk_uri sk ;
return sk
let decrypt_all (cctxt : #Client_context.io_wallet) =
Secret_key.load cctxt >>=? fun sks ->
Lwt.try_bind
(fun () -> ask_all_passwords cctxt sks)
(fun _ -> return ())
(fun _ -> failwith "Corrupted secret key database. Aborting.")
iter_s begin fun (name, sk_uri) ->
if Uri.scheme (sk_uri : sk_uri :> Uri.t) <> Some scheme then
return ()
else
decrypt cctxt ~name sk_uri >>=? fun _ ->
return ()
end sks
let input_new_passphrase (cctxt : #Client_context.io_wallet) =
cctxt#prompt_password "Enter passphrase to encrypt your key: " >>=? fun password ->
cctxt#prompt_password "Confirm passphrase: " >>=? fun confirm ->
if password <> confirm then
failwith "Passphrases do not match."
else return password
let rec read_passphrase (cctxt : #Client_context.io) =
cctxt#prompt_password
"Enter passphrase to encrypt your key: " >>=? fun password ->
cctxt#prompt_password
"Confirm passphrase: " >>=? fun confirm ->
if not (MBytes.equal password confirm) then
cctxt#message "Passphrases do not match." >>= fun () ->
read_passphrase cctxt
else
return password
let encrypt_sk cctxt sk =
input_new_passphrase cctxt >>=? fun password ->
let salt = Rand.generate salt_len in
let key = Crypto_box.Secretbox.unsafe_of_bytes (pbkdf ~password ~salt) in
let msg = Data_encoding.Binary.to_bytes_exn Signature.Secret_key.encoding sk in
let encrypted_passwd = Crypto_box.Secretbox.box key msg nonce in
let payload = MBytes.(to_string (concat "" [salt; encrypted_passwd])) in
let location = Base58.safe_encode payload in
Hashtbl.replace decrypted_sks location sk ;
return (Secret_key_locator.create ~scheme ~location:[location])
let encrypt cctxt sk =
read_passphrase cctxt >>=? fun password ->
let payload = Raw.encrypt ~password sk in
let path = Base58.safe_encode (MBytes.to_string payload) in
let sk_uri = Client_keys.make_sk_uri (Uri.make ~scheme ~path ()) in
Hashtbl.replace decrypted sk_uri sk ;
return sk_uri
let rec get_boolean_answer (cctxt : #Client_context.io_wallet) ~default ~msg =
let prompt = if default then "(Y/n/q)" else "(y/N/q)" in
cctxt#prompt "%s %s: " msg prompt >>=? fun gen ->
match default, String.lowercase_ascii gen with
| default, "" -> return default
| _, "y" -> return true
| _, "n" -> return false
| _, "q" -> failwith "Exit by user request."
| _ -> get_boolean_answer cctxt ~msg ~default
(*
let rec sk_of_mnemonic (cctxt : #Client_context.io_wallet) =
cctxt#prompt "Enter the e-mail used for the paper wallet: " >>=? fun email ->
let rec loop_words acc i =
if i > 14 then return (List.rev acc) else
cctxt#prompt_password "Enter word %d: " i >>=? fun word ->
match Bip39.index_of_word (MBytes.to_string word) with
| None -> loop_words acc i
| Some wordidx -> loop_words (wordidx :: acc) (succ i) in
loop_words [] 0 >>=? fun words ->
match Bip39.of_indices words with
| None -> assert false
| Some t ->
cctxt#prompt_password
"Enter the password used for the paper wallet: " >>=? fun password ->
(* TODO: unicode normalization (NFKD)... *)
let sk = Bip39.to_seed ~passphrase:(email ^ MBytes.to_string password) t in
let sk = Cstruct.(to_bigarray (sub sk 0 32)) in
let sk : Signature.Secret_key.t =
Ed25519
(Data_encoding.Binary.of_bytes_exn Ed25519.Secret_key.encoding sk) in
let pk = Signature.Secret_key.to_public_key sk in
let pkh = Signature.Public_key.hash pk in
let msg = Format.asprintf
"Your public Tezos address is %a is that correct?"
Signature.Public_key_hash.pp pkh in
get_boolean_answer cctxt ~msg ~default:true >>=? function
| true -> return sk
| false -> sk_of_mnemonic cctxt
let rec get_boolean_answer (cctxt : #Client_context.io_wallet) ~default ~msg =
let prompt = if default then "(Y/n/q)" else "(y/N/q)" in
cctxt#prompt "%s %s: " msg prompt >>= fun gen ->
match default, String.lowercase_ascii gen with
| default, "" -> return default
| _, "y" -> return true
| _, "n" -> return false
| _, "q" -> failwith "Exit by user request."
| _ -> get_boolean_answer cctxt ~msg ~default
let rec sk_of_mnemonic (cctxt : #Client_context.io_wallet) =
cctxt#prompt "Enter the e-mail used for the paper wallet: " >>= fun email ->
let rec loop_words acc i =
if i > 14 then Lwt.return (List.rev acc) else
cctxt#prompt_password "Enter word %d: " i >>= fun word ->
match Bip39.index_of_word word with
| None -> loop_words acc i
| Some wordidx -> loop_words (wordidx :: acc) (succ i) in
loop_words [] 0 >>= fun words ->
match Bip39.of_indices words with
| None -> assert false
| Some t ->
cctxt#prompt_password
"Enter the password used for the paper wallet: " >>= fun password ->
(* TODO: unicode normalization (NFKD)... *)
let sk = Bip39.to_seed ~passphrase:(email ^ password) t in
let sk = Cstruct.(to_bigarray (sub sk 0 32)) in
let sk : Signature.Secret_key.t =
Ed25519
(Data_encoding.Binary.of_bytes_exn Ed25519.Secret_key.encoding sk) in
let pk = Signature.Secret_key.to_public_key sk in
let pkh = Signature.Public_key.hash pk in
let msg = Format.asprintf
"Your public Tezos address is %a is that correct?"
Signature.Public_key_hash.pp pkh in
get_boolean_answer cctxt ~msg ~default:true >>=? function
| true -> return sk
| false -> sk_of_mnemonic cctxt
*)
(*
let sk_locator_of_human_input cctxt = function
| sk :: _ ->
Lwt.return (Signature.Secret_key.of_b58check sk) >>=? fun sk ->
@ -176,37 +179,38 @@ let sk_locator_of_human_input cctxt = function
sk_of_mnemonic cctxt >>=? fun sk ->
encrypt_sk cctxt sk
end
*)
(*
let pk_locator_of_human_input _cctxt = function
| [] -> failwith "Missing public key argument."
| pk :: _ -> return (Public_key_locator.create ~scheme ~location:[pk])
*)
let sk_of_locator = function
| (Sk_locator { location = [location] }) -> begin
match Hashtbl.find decrypted_sks location with
| exception Not_found -> failwith "Unknown secret key location."
| sk -> return sk
end
| (Sk_locator { location = _ }) ->
failwith "Wrong location type."
let pk_of_locator = function
|(Pk_locator { location = [location] }) ->
Lwt.return (Signature.Public_key.of_b58check location)
|(Pk_locator { location = _ }) ->
failwith "Wrong location type."
module Make(C : sig val cctxt: Client_context.prompter end) = struct
let sk_to_locator sk =
Secret_key_locator.create
~scheme ~location:[Signature.Secret_key.to_b58check sk] |>
Lwt.return
let scheme = "encrypted"
let pk_to_locator pk =
Public_key_locator.create
~scheme ~location:[Signature.Public_key.to_b58check pk] |>
Lwt.return
let title =
"Built-in signer using encrypted keys."
let neuterize x = Lwt.return (Signature.Secret_key.to_public_key x)
let public_key x = return x
let public_key_hash x = return (Signature.Public_key.hash x)
let sign ?watermark t buf = return (Signature.sign ?watermark t buf)
let description =
"If you try to import a secret key without additional argument, you will \
be asked to either generate a new key, or to import the elements \
from your fundraiser paper wallet.\n\
If you add an argument when importing a secret key, \
the format is the raw Base58-encoded key (starting with 'edsk').\n\
The format for importing public keys is the raw Base58-encoded \
key (starting with 'edpk')."
let public_key = Unencrypted.public_key
let public_key_hash = Unencrypted.public_key_hash
let neuterize sk_uri =
decrypt C.cctxt sk_uri >>=? fun sk ->
return (Unencrypted.make_pk (Signature.Secret_key.to_public_key sk))
let sign ?watermark sk_uri buf =
decrypt C.cctxt sk_uri >>=? fun sk ->
return (Signature.sign ?watermark sk buf)
end

View File

@ -7,4 +7,16 @@
(* *)
(**************************************************************************)
include Client_keys.SIGNER
module Make(C : sig val cctxt: Client_context.prompter end) : Client_keys.SIGNER
val decrypt:
#Client_context.io_wallet ->
?name:string ->
Client_keys.sk_uri -> Signature.secret_key tzresult Lwt.t
val decrypt_all:
#Client_context.io_wallet -> unit tzresult Lwt.t
val encrypt:
#Client_context.io ->
Signature.secret_key -> Client_keys.sk_uri tzresult Lwt.t

View File

@ -0,0 +1,49 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
open Client_keys
let scheme = "https"
let title = "..."
let description = "..."
let parse uri =
let path = String.split '/' (Uri.path uri) in
match List.rev path with
| [] -> invalid_arg "..."
| key :: rev_path ->
Lwt.return (Signature.Public_key_hash.of_b58check key) >>=? fun key ->
return (Uri.with_path uri (String.concat "/" (List.rev rev_path)),
key)
let public_key uri =
parse (uri : pk_uri :> Uri.t) >>=? fun (base, pkh) ->
RPC_client.call_service
Media_type.all_media_types
~base Signer_services.public_key ((), pkh) () ()
let neuterize uri =
return (Client_keys.make_pk_uri (uri : sk_uri :> Uri.t))
let public_key_hash uri =
public_key uri >>=? fun pk ->
return (Signature.Public_key.hash pk)
let sign ?watermark uri msg =
parse (uri : sk_uri :> Uri.t) >>=? fun (base, pkh) ->
let msg =
match watermark with
| None -> msg
| Some watermark ->
MBytes.concat "" [ Signature.bytes_of_watermark watermark ; msg ] in
RPC_client.call_service
Media_type.all_media_types
~base Signer_services.sign ((), pkh) () msg

View File

@ -1,6 +1,6 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2017. *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)

View File

@ -14,8 +14,7 @@
-open Tezos_stdlib_unix
-open Tezos_client_base
-open Tezos_signer_services
-open Tezos_rpc_http
-w -9))))
-open Tezos_rpc_http))))
(alias
((name runtest_indent)

View File

@ -1,172 +0,0 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
open Client_keys
open Signer_messages
type path =
| Socket of Lwt_utils_unix.Socket.addr
| Https of string * int
let socket_sign path pkh data =
let req = { Sign.Request.pkh ; data } in
Lwt_utils_unix.Socket.connect path >>=? fun conn ->
Lwt_utils_unix.Socket.send conn Request.encoding (Request.Sign req) >>=? fun () ->
let encoding = result_encoding Sign.Response.encoding in
Lwt_utils_unix.Socket.recv conn encoding >>=? fun res ->
Lwt_unix.close conn >>= fun () ->
Lwt.return res
let socket_request_public_key path pkh =
Lwt_utils_unix.Socket.connect path >>=? fun conn ->
Lwt_utils_unix.Socket.send conn Request.encoding (Request.Public_key pkh) >>=? fun () ->
let encoding = result_encoding Public_key.Response.encoding in
Lwt_utils_unix.Socket.recv conn encoding >>=? fun res ->
Lwt_unix.close conn >>= fun () ->
Lwt.return res
let sign path pkh data =
match path with
| Socket path -> socket_sign path pkh data
| Https (host, port) ->
RPC_client.call_service
Media_type.all_media_types
~base: (Uri.of_string (Format.asprintf "https://%s:%d" host port))
Signer_services.sign ((), pkh) () data
let request_public_key path pkh =
match path with
| Socket path -> socket_request_public_key path pkh
| Https (host, port) ->
RPC_client.call_service
Media_type.all_media_types
~base: (Uri.of_string (Format.asprintf "https://%s:%d" host port))
Signer_services.public_key ((), pkh) () ()
module Remote_signer : SIGNER = struct
let scheme = "remote"
let title =
"Built-in tezos-signer using remote wallet."
let description =
"Valid locators are one of these two forms:\n\
\ - unix [path to local signer socket] <remote key alias>\n\
\ - tcp [host] [port] <remote key alias>\n\
\ - https [host] [port] <remote key alias>\n\
All fields except the key can be of the form '$VAR', \
in which case their value is taken from environment variable \
VAR each time the key is accessed.\n\
Not specifiyng fields sets them to $TEZOS_SIGNER_UNIX_PATH, \
$TEZOS_SIGNER_TCP_HOST and $TEZOS_SIGNER_TCP_PORT, \
$TEZOS_SIGNER_HTTPS_HOST and $TEZOS_SIGNER_HTTPS_PORT, \
that get evaluated to default values '$HOME/.tezos-signer-socket', \
localhost and 6732, and can be set later on."
type key_path = path * Signature.Public_key_hash.t
(* secret key is the identifier of the location key identifier *)
type secret_key = key_path
(* public key is the identifier of the location key identifier *)
type public_key = key_path * Signature.Public_key.t
let pks : (secret_key, Signature.Public_key.t) Hashtbl.t = Hashtbl.create 53
(* load and init the remote wallet. initialize the connection *)
let init _cctxt = return ()
let path_of_human_input = function
| "unix" :: key :: [] ->
return (Socket (Unix "$TEZOS_SIGNER_UNIX_PATH"),
Signature.Public_key_hash.of_b58check_exn key)
| "unix" :: file :: key :: [] ->
return (Socket (Unix file),
Signature.Public_key_hash.of_b58check_exn key)
| "tcp" :: host :: port :: key :: [] ->
return (Socket (Tcp (host, int_of_string port)),
Signature.Public_key_hash.of_b58check_exn key)
(* Temporary FIXME *)
(* | "tcp" :: host :: key :: [] -> *)
(* return (Socket (Tcp (host, "$TEZOS_SIGNER_TCP_PORT")), key) *)
(* | "tcp" :: key :: [] -> *)
(* return (Socket (Tcp ("$TEZOS_SIGNER_TCP_HOST", "$TEZOS_SIGNER_TCP_PORT")), key) *)
| "https" :: host :: port :: key :: [] ->
return (Https (host, int_of_string port),
Signature.Public_key_hash.of_b58check_exn key)
(* Temporary FIXME *)
(* | "https" :: host :: key :: [] -> *)
(* return (Https (host, "$TEZOS_SIGNER_HTTPS_PORT"), key) *)
(* | "https" :: key :: [] -> *)
(* return (Https ("$TEZOS_SIGNER_HTTPS_HOST", "$TEZOS_SIGNER_HTTPS_PORT"), key) *)
| location ->
failwith
"@[<v 2>Remote Schema : wrong locator %s.@,@[<hov 0>%a@]@]"
(Secret_key_locator.to_string (Secret_key_locator.create ~scheme ~location))
Format.pp_print_text description
let locator_of_path = function
| Socket (Unix path), key -> [ "unix" ; path ; Signature.Public_key_hash.to_b58check key ]
| Socket (Tcp (host, port)), key -> [ "tcp" ; host ; string_of_int port ; Signature.Public_key_hash.to_b58check key ]
| Https (host, port), key -> [ "https" ; host ; string_of_int port ; Signature.Public_key_hash.to_b58check key ]
let pk_locator_of_human_input _cctxt path =
path_of_human_input path >>=? fun pk ->
let location = locator_of_path pk in
return (Public_key_locator.create ~scheme ~location)
let sk_to_locator sk =
let location = locator_of_path sk in
Lwt.return (Secret_key_locator.create ~scheme ~location)
let sk_locator_of_human_input _cctxt input =
path_of_human_input input >>=? fun (path, key) ->
request_public_key path key >>=? fun pk ->
Hashtbl.replace pks (path, key) pk ;
sk_to_locator (path,key) >>= fun locator ->
return locator
let sk_of_locator loc =
path_of_human_input (Secret_key_locator.location loc)
let pk_of_locator loc =
path_of_human_input (Public_key_locator.location loc) >>=? fun (path, key) ->
request_public_key path key >>=? fun pk ->
Hashtbl.replace pks (path, key) pk ;
return ((path, key), pk)
let pk_to_locator (path, _) =
let location = locator_of_path path in
Lwt.return (Public_key_locator.create ~scheme ~location)
let neuterize ((path, key) as sk) =
match Hashtbl.find_opt pks sk with
| Some pk -> Lwt.return (sk, pk)
| None -> begin
request_public_key path key >>= function
| Error _ -> Lwt.fail_with "Remote : Cannot obtain public key from remote signer"
| Ok pk -> begin
Hashtbl.replace pks sk pk ;
Lwt.return (sk, pk)
end
end
let public_key (_, x) = return x
let public_key_hash (_, x) = return (Signature.Public_key.hash x)
let sign ?watermark (path, key) msg =
let msg =
match watermark with
| None -> msg
| Some watermark ->
MBytes.concat "" [ Signature.bytes_of_watermark watermark ; msg ] in
sign path key msg
end
include Remote_signer

View File

@ -0,0 +1,105 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
open Client_keys
open Signer_messages
let sign ?watermark path pkh msg =
let msg =
match watermark with
| None -> msg
| Some watermark ->
MBytes.concat "" [ Signature.bytes_of_watermark watermark ; msg ] in
let req = { Sign.Request.pkh ; data = msg } in
Lwt_utils_unix.Socket.connect path >>=? fun conn ->
Lwt_utils_unix.Socket.send
conn Request.encoding (Request.Sign req) >>=? fun () ->
let encoding = result_encoding Sign.Response.encoding in
Lwt_utils_unix.Socket.recv conn encoding >>=? fun res ->
Lwt_unix.close conn >>= fun () ->
Lwt.return res
let public_key path pkh =
Lwt_utils_unix.Socket.connect path >>=? fun conn ->
Lwt_utils_unix.Socket.send
conn Request.encoding (Request.Public_key pkh) >>=? fun () ->
let encoding = result_encoding Public_key.Response.encoding in
Lwt_utils_unix.Socket.recv conn encoding >>=? fun res ->
Lwt_unix.close conn >>= fun () ->
Lwt.return res
module Unix = struct
let scheme = "unix"
let title = "..."
let description = "..."
let parse uri =
match Uri.get_query_param uri "key" with
| None -> invalid_arg "... FIXME ... B"
| Some key ->
Lwt.return (Signature.Public_key_hash.of_b58check key) >>=? fun key ->
return (Lwt_utils_unix.Socket.Unix (Uri.path uri), key)
let public_key uri =
parse (uri : pk_uri :> Uri.t) >>=? fun (path, pkh) ->
public_key path pkh
let neuterize uri =
return (Client_keys.make_pk_uri (uri : sk_uri :> Uri.t))
let public_key_hash uri =
public_key uri >>=? fun pk ->
return (Signature.Public_key.hash pk)
let sign ?watermark uri msg =
parse (uri : sk_uri :> Uri.t) >>=? fun (path, pkh) ->
sign ?watermark path pkh msg
end
module Tcp = struct
let scheme = "tcp"
let title = "..."
let description = "..."
(* let init _cctxt = return () *)
let parse uri =
match Uri.get_query_param uri "key" with
| None -> invalid_arg "... FIXME ... C"
| Some key ->
Lwt.return (Signature.Public_key_hash.of_b58check key) >>=? fun key ->
match Uri.host uri, Uri.port uri with
| None, _ | _, None ->
invalid_arg "... FIXME ... C2"
| Some path, Some port ->
return (Lwt_utils_unix.Socket.Tcp (path, port), key)
let public_key uri =
parse (uri : pk_uri :> Uri.t) >>=? fun (path, pkh) ->
public_key path pkh
let neuterize uri =
return (Client_keys.make_pk_uri (uri : sk_uri :> Uri.t))
let public_key_hash uri =
public_key uri >>=? fun pk ->
return (Signature.Public_key.hash pk)
let sign ?watermark uri msg =
parse (uri : sk_uri :> Uri.t) >>=? fun (path, pkh) ->
sign ?watermark path pkh msg
end

View File

@ -0,0 +1,11 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
module Unix : Client_keys.SIGNER
module Tcp : Client_keys.SIGNER

View File

@ -22,11 +22,7 @@ let description =
The format for importing public keys is the raw Base58-encoded \
key (starting with 'edpk')."
type secret_key = Signature.Secret_key.t
type public_key = Signature.Public_key.t
let init _wallet = return ()
(*
let sk_locator_of_human_input _cctxt = function
| sk :: _ ->
return (Secret_key_locator.create ~scheme ~location:[sk])
@ -39,30 +35,31 @@ let pk_locator_of_human_input _cctxt = function
| [] -> failwith "Missing public key argument"
| pk :: _ -> return (Public_key_locator.create ~scheme ~location:[pk])
let sk_of_locator = function
|(Sk_locator { location = ( location :: _ ) }) ->
Lwt.return (Signature.Secret_key.of_b58check location)
|(Sk_locator { location = _ }) ->
failwith "Wrong type of location"
let pk_of_locator = function
|(Pk_locator { location = ( location :: _ ) }) ->
Lwt.return (Signature.Public_key.of_b58check location)
|(Pk_locator { location = _ }) ->
failwith "Wrong type of location"
let sk_to_locator sk =
Secret_key_locator.create
~scheme ~location:[Signature.Secret_key.to_b58check sk] |>
*)
let secret_key sk_uri =
Lwt.return
(Signature.Secret_key.of_b58check (Uri.path (sk_uri : sk_uri :> Uri.t)))
let pk_to_locator pk =
Public_key_locator.create
~scheme ~location:[Signature.Public_key.to_b58check pk] |>
let make_sk sk =
Client_keys.make_sk_uri
(Uri.make ~scheme ~path:(Signature.Secret_key.to_b58check sk) ())
let public_key pk_uri =
Lwt.return
(Signature.Public_key.of_b58check (Uri.path (pk_uri : pk_uri :> Uri.t)))
let neuterize x = Lwt.return (Signature.Secret_key.to_public_key x)
let public_key x = return x
let public_key_hash x = return (Signature.Public_key.hash x)
let sign ?watermark t buf = return (Signature.sign ?watermark t buf)
let make_pk pk =
Client_keys.make_pk_uri
(Uri.make ~scheme ~path:(Signature.Public_key.to_b58check pk) ())
let neuterize sk_uri =
secret_key sk_uri >>=? fun sk ->
return (make_pk (Signature.Secret_key.to_public_key sk))
let public_key_hash pk_uri =
public_key pk_uri >>=? fun pk ->
return (Signature.Public_key.hash pk)
let sign ?watermark sk_uri buf =
secret_key sk_uri >>=? fun sk ->
return (Signature.sign ?watermark sk buf)

View File

@ -8,3 +8,6 @@
(**************************************************************************)
include Client_keys.SIGNER
val make_pk: Signature.public_key -> Client_keys.pk_uri
val make_sk: Signature.secret_key -> Client_keys.sk_uri

View File

@ -103,7 +103,7 @@ let inject_endorsement (cctxt : #Proto_alpha.full)
~slots
() >>=? fun bytes ->
Client_keys.append
cctxt src_sk ~watermark:Endorsement bytes >>=? fun signed_bytes ->
src_sk ~watermark:Endorsement bytes >>=? fun signed_bytes ->
Shell_services.inject_operation
cctxt ?async ~chain_id:bi.chain_id signed_bytes >>=? fun oph ->
iter_s

View File

@ -31,8 +31,7 @@ let forge_block_header
{ priority ; seed_nonce_hash ; proof_of_work_nonce } in
if Baking.check_header_proof_of_work_stamp shell protocol_data stamp_threshold then
let unsigned_header = Block_header.forge_unsigned shell protocol_data in
Client_keys.append cctxt
delegate_sk ~watermark:Block_header unsigned_header
Client_keys.append delegate_sk ~watermark:Block_header unsigned_header
else
loop () in
loop ()

View File

@ -114,9 +114,10 @@ let vote_protocol_parameters =
let activate_alpha ?(vote = false) () =
let fitness = Fitness_repr.from_int64 0L in
let dictator_sk = Client_keys.Secret_key_locator.create
~scheme:"unencrypted"
~location:["edsk31vznjHSSpGExDMHYASz45VZqXN4DPxvsa4hAyY8dHM28cZzp6"] in
let dictator_sk =
Tezos_signer_backends.Unencrypted.make_sk
(Signature.Secret_key.of_b58check_exn
"edsk31vznjHSSpGExDMHYASz45VZqXN4DPxvsa4hAyY8dHM28cZzp6") in
let protocol_parameters =
if vote then vote_protocol_parameters else protocol_parameters in
Tezos_client_genesis.Client_proto_main.bake
@ -248,9 +249,8 @@ module Account = struct
~(account:t)
~destination
~amount () =
let src_sk = Client_keys.Secret_key_locator.create
~scheme:"unencrypted"
~location:[Signature.Secret_key.to_b58check account.sk] in
let src_sk =
Tezos_signer_backends.Unencrypted.make_sk account.sk in
Client_proto_context.transfer
(new wrap_full (no_write_context !rpc_config ~block))
block
@ -272,9 +272,8 @@ module Account = struct
let delegatable, delegate = match delegate with
| None -> false, None
| Some delegate -> true, Some delegate in
let src_sk = Client_keys.Secret_key_locator.create
~scheme:"unencrypted"
~location:[Signature.Secret_key.to_b58check src.sk] in
let src_sk =
Tezos_signer_backends.Unencrypted.make_sk src.sk in
Client_proto_context.originate_account
~source:src.contract
~src_pk:src.pk
@ -506,9 +505,8 @@ module Baking = struct
Some (Nonce.hash seed_nonce)
else
None in
let src_sk = Client_keys.Secret_key_locator.create
~scheme:"unencrypted"
~location:[Signature.Secret_key.to_b58check contract.sk] in
let src_sk =
Tezos_signer_backends.Unencrypted.make_sk contract.sk in
Client_baking_forge.forge_block
ctxt
block

View File

@ -84,7 +84,7 @@ module Account : sig
?block:Block_services.block ->
?fee: Tez.t ->
contract:Contract.t ->
manager_sk:Client_keys.Secret_key_locator.t ->
manager_sk:Client_keys.sk_uri ->
src_pk:public_key ->
public_key_hash option ->
Operation_hash.t tzresult Lwt.t

View File

@ -55,7 +55,7 @@ let transfer cctxt
~destination ?parameters ~fee () >>=? fun bytes ->
Block_services.predecessor cctxt block >>=? fun predecessor ->
Client_keys.sign
cctxt src_sk ~watermark:Generic_operation bytes >>=? fun signature ->
src_sk ~watermark:Generic_operation bytes >>=? fun signature ->
let signed_bytes = Signature.concat bytes signature in
let oph = Operation_hash.hash_bytes [ signed_bytes ] in
Alpha_services.Helpers.apply_operation cctxt block
@ -74,7 +74,7 @@ let reveal cctxt
cctxt block
~branch ~source ~sourcePubKey:src_pk ~counter ~fee () >>=? fun bytes ->
Client_keys.sign
cctxt src_sk ~watermark:Generic_operation bytes >>=? fun signature ->
src_sk ~watermark:Generic_operation bytes >>=? fun signature ->
let signed_bytes = Signature.concat bytes signature in
let oph = Operation_hash.hash_bytes [ signed_bytes ] in
Shell_services.inject_operation
@ -123,7 +123,7 @@ let originate_account ?branch
~counter ~balance ~spendable:true
?delegatable ?delegatePubKey:delegate ~fee () >>=? fun bytes ->
Client_keys.sign
cctxt src_sk ~watermark:Generic_operation bytes >>=? fun signature ->
src_sk ~watermark:Generic_operation bytes >>=? fun signature ->
originate cctxt ~block ~chain_id ~signature bytes
let delegate_contract cctxt
@ -138,7 +138,7 @@ let delegate_contract cctxt
~branch ~source ?sourcePubKey:src_pk ~counter ~fee delegate_opt
>>=? fun bytes ->
Client_keys.sign
cctxt manager_sk ~watermark:Generic_operation bytes >>=? fun signature ->
manager_sk ~watermark:Generic_operation bytes >>=? fun signature ->
let signed_bytes = Signature.concat bytes signature in
let oph = Operation_hash.hash_bytes [ signed_bytes ] in
Shell_services.inject_operation
@ -241,7 +241,7 @@ let originate_contract
~delegatable ?delegatePubKey:delegate
~script:{ code ; storage } ~fee () >>=? fun bytes ->
Client_keys.sign
cctxt src_sk ~watermark:Generic_operation bytes >>=? fun signature ->
src_sk ~watermark:Generic_operation bytes >>=? fun signature ->
originate cctxt ~block ~signature bytes
let wait_for_operation_inclusion
@ -345,15 +345,17 @@ let claim_commitment (cctxt : #Proto_alpha.full)
Shell_services.inject_operation
cctxt ~chain_id:bi.chain_id bytes >>=? fun oph ->
operation_submitted_message cctxt oph >>=? fun () ->
let pk_uri = Tezos_signer_backends.Unencrypted.make_pk pk in
let sk_uri = Tezos_signer_backends.Unencrypted.make_sk sk in
begin
match confirmations with
| None ->
Client_keys.register_key cctxt ?force (pkh, pk, sk) name >>=? fun () ->
Client_keys.register_key cctxt ?force (pkh, pk_uri, sk_uri) name >>=? fun () ->
return ()
| Some confirmations ->
cctxt#message "Waiting for the operation to be included..." >>= fun () ->
wait_for_operation_inclusion ~confirmations cctxt oph >>=? fun () ->
Client_keys.register_key cctxt ?force (pkh, pk, sk) name >>=? fun () ->
Client_keys.register_key cctxt ?force (pkh, pk_uri, sk_uri) name >>=? fun () ->
Alpha_services.Contract.balance
cctxt (`Head 0) (Contract.implicit_contract pkh) >>=? fun balance ->
cctxt#message "Account %s (%a) created with %s%a."

View File

@ -119,7 +119,7 @@ let trace
let hash_and_sign (data : Michelson_v1_parser.parsed) (typ : Michelson_v1_parser.parsed) sk block cctxt =
Alpha_services.Helpers.hash_data cctxt block (data.expanded, typ.expanded) >>=? fun hash ->
Client_keys.sign cctxt sk (MBytes.of_string hash) >>=? fun signature ->
Client_keys.sign sk (MBytes.of_string hash) >>=? fun signature ->
let `Hex signature = Signature.to_hex signature in
return (hash, signature)

View File

@ -9,6 +9,7 @@
tezos-shell-services
tezos-client-base
tezos-rpc
tezos-signer-backends
bip39))
(library_flags (:standard -linkall))
(flags (:standard -w -9+27-30-32-40@8

View File

@ -21,7 +21,7 @@ let bake cctxt ?(timestamp = Time.now ()) block command sk =
let blk =
Data_encoding.Binary.to_bytes_exn Block_header.encoding
{ shell = shell_header ; protocol_data } in
Client_keys.append cctxt sk blk >>=? fun signed_blk ->
Client_keys.append sk blk >>=? fun signed_blk ->
Shell_services.inject_block cctxt signed_blk []
let int64_parameter =