123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)typeerror+=Unregistered_key_schemeofstringtypeerror+=Wrong_key_schemeof(string*string)typeerror+=Invalid_uriofUri.tlet()=register_error_kind`Permanent~id:"cli.unregistered_key_scheme"~title:"Unregistered key scheme"~description:"A key has been provided with an unregistered scheme (no corresponding \
plugin)"~pp:(funppfs->Format.fprintfppf"No matching plugin for key scheme %s"s)Data_encoding.(obj1(req"value"string))(functionUnregistered_key_schemes->Somes|_->None)(funs->Unregistered_key_schemes);register_error_kind`Permanent~id:"cli.key.invalid_uri"~title:"Invalid key uri"~description:"A key has been provided with an invalid uri."~pp:(funppfs->Format.fprintfppf"Cannot parse the key uri: %s"s)Data_encoding.(obj1(req"value"string))(functionInvalid_uris->Some(Uri.to_strings)|_->None)(funs->Invalid_uri(Uri.of_strings));register_error_kind`Permanent~id:"cli.wrong_key_scheme"~title:"Wrong key scheme"~description:"A certain scheme type has been requested but another one was found"~pp:(funppf(expected,found)->Format.fprintfppf"Expected a %s scheme found a %s one"expectedfound)Data_encoding.(obj2(req"expected"string)(req"found"string))(function|Wrong_key_scheme(expected,found)->Some(expected,found)|_->None)(fun(expected,found)->Wrong_key_scheme(expected,found))moduleLogging=structlettag=Tag.def~doc:"Identity""pk_alias"Format.pp_print_textendleturi_encoding=letto_uris=leto=Uri.of_stringsinmatchUri.schemeowith|None->Stdlib.failwith"Key URI needs a scheme"|Some_->oinData_encoding.(convUri.to_stringto_uristring)typeerror+=Unexisting_schemeofUri.tlet()=register_error_kind`Permanent~id:"cli.unexisting_scheme"~title:"Unexisting scheme"~description:"The requested scheme does not exist"~pp:(funppfuri->Format.fprintfppf"The uri %a does specify a scheme to use"Uri.pp_humuri)Data_encoding.(obj1(req"uri"uri_encoding))(functionUnexisting_schemeuri->Someuri|_->None)(funuri->Unexisting_schemeuri)typepk_uri=Uri.tmodulePk_uri_hashtbl=Hashtbl.Make(structtypet=pk_uriletequal=Uri.equallethash=Hashtbl.hashend)letmake_pk_uri(x:Uri.t):pk_uritzresult=letopenResult_syntaxinmatchUri.schemexwith|None->tzfail(Exn(Failure"Error while parsing URI: PK_URI needs a scheme"))|Some_->returnxtypesk_uri=Uri.tmoduleCompareUri=Compare.Make(structtypet=Uri.tletcompare=Uri.compareend)letmake_sk_uri(x:Uri.t):sk_uritzresult=letopenResult_syntaxinmatchUri.schemexwith|None->tzfail(Exn(Failure"Error while parsing URI: SK_URI needs a scheme"))|Some_->returnxtypeerror+=Signature_mismatchofsk_urilet()=register_error_kind`Permanent~id:"cli.signature_mismatch"~title:"Signature mismatch"~description:"The signer produced an invalid signature"~pp:(funppfsk->Format.fprintfppf"The signer for %a produced an invalid signature"Uri.pp_humsk)Data_encoding.(obj1(req"locator"uri_encoding))(functionSignature_mismatchsk->Somesk|_->None)(funsk->Signature_mismatchsk)typesapling_uri=Uri.tletmake_sapling_uri(x:Uri.t):sapling_uritzresult=letopenResult_syntaxinmatchUri.schemexwith|None->tzfail(Exn(Failure"SAPLING_URI needs a scheme"))|Some_->returnxtypeaggregate_pk_uri=Uri.ttypeaggregate_sk_uri=Uri.tletmake_aggregate_pk_uri(x:Uri.t):aggregate_pk_uritzresult=letopenResult_syntaxinmatchUri.schemexwith|None->tzfail(Exn(Failure"Error while parsing URI: AGGREGATE_PK_URI needs a scheme"))(* because it's possible to make an aggregate pk uri without having the signer
in the client we can't check that scheme is linked to a known signer *)|Some_->returnxletmake_aggregate_sk_uri(x:Uri.t):aggregate_sk_uritzresult=letopenResult_syntaxinmatchUri.schemexwith|None->tzfail(Exn(Failure"Error while parsing URI: AGGREGATE_SK_URI needs a scheme"))|Some_->returnxletpk_uri_parameter()=Tezos_clic.parameter(fun_s->Lwt.return@@make_pk_uri(Uri.of_strings))letpk_uri_param?name?descparams=letname=Option.value~default:"uri"nameinletdesc=Option.value~default:"public key\n\
Varies from one scheme to the other.\n\
Use command `list signing schemes` for more information."descinTezos_clic.param~name~desc(pk_uri_parameter())paramsletsk_uri_parameter()=Tezos_clic.parameter(fun_s->Lwt.return(make_sk_uri@@Uri.of_strings))letsk_uri_param?name?descparams=letname=Option.value~default:"uri"nameinletdesc=Option.value~default:"secret key\n\
Varies from one scheme to the other.\n\
Use command `list signing schemes` for more information."descinTezos_clic.param~name~desc(sk_uri_parameter())paramsletaggregate_sk_uri_parameter()=Tezos_clic.parameter(fun_s->make_aggregate_sk_uri@@Uri.of_strings|>Lwt.return)letaggregate_sk_uri_param?name?descparams=letname=Option.value~default:"uri"nameinletdesc=Option.value~default:"secret key\n\
Varies from one scheme to the other.\n\
Use command `list signing schemes` for more information."descinTezos_clic.param~name~desc(aggregate_sk_uri_parameter())paramstypesapling_key={sk:sapling_uri;(* zip32 derivation path *)path:int32list;(* index of the next address to generate *)address_index:Tezos_sapling.Core.Client.Viewing_key.index;}moduleSapling_key=Client_aliases.Alias(structmoduleS=Tezos_sapling.Core.Clientletname="sapling_key"typet=sapling_keyincludeCompare.Make(structtypenonrect=tletcompareab=Compare.or_else(CompareUri.comparea.skb.sk)(fun()->Compare.or_else(Stdlib.comparea.pathb.path)(fun()->Tezos_sapling.Core.Client.Viewing_key.compare_indexa.address_indexb.address_index))end)letencoding=letopenData_encodinginconv(funk->(k.sk,k.path,k.address_index))(fun(sk,path,address_index)->{sk;path;address_index})(obj3(req"sk"uri_encoding)(req"path"(listint32))(req"address_index"S.Viewing_key.index_encoding))letof_sources=letopenLwt_result_syntaxinletopenData_encodinginmatchJson.from_stringswith|Error_->failwith"corrupted wallet"|Oks->return(Json.destructencodings)letto_sourcek=letopenData_encodinginLwt.return_ok@@Json.to_string(Json.constructencodingk)end)moduleAggregate_alias=structmodulePublic_key_hash=structincludeClient_aliases.Alias(struct(* includes t, Compare, encoding, of/to_b58check *)includeTezos_crypto.Aggregate_signature.Public_key_hashletof_sources=Lwt.return(of_b58checks)letto_sourcep=Lwt_result_syntax.return(to_b58checkp)letname="Aggregate_public_key_hash"end)endtypepk_uri=Uri.tletmake_pk_uri(x:Uri.t):pk_uritzresult=letopenResult_syntaxinmatchUri.schemexwith|None->tzfail(Exn(Failure"Error while parsing URI: AGGREGATE_PK_URI needs a scheme"))|Some_->returnxmodulePublic_key=Client_aliases.Alias(structletname="Aggregate_public_key"typet=pk_uri*Tezos_crypto.Aggregate_signature.Public_key.toptionincludeCompare.Make(structtypenonrect=tletcompare(apk,aso)(bpk,bso)=Compare.or_else(CompareUri.compareapkbpk)(fun()->Option.compareTezos_crypto.Aggregate_signature.Public_key.compareasobso)end)letof_sources=letopenLwt_result_syntaxinlet*?pk_uri=make_pk_uri@@Uri.of_stringsinreturn(pk_uri,None)letto_source(t,_)=Lwt_result_syntax.return(Uri.to_stringt)letencoding=letopenData_encodinginunion[caseJson_onlyuri_encoding~title:"Locator_only"(functionuri,None->Someuri|_,Some_->None)(funuri->(uri,None));caseJson_only~title:"Locator_and_full_key"(obj2(req"locator"uri_encoding)(req"key"Tezos_crypto.Aggregate_signature.Public_key.encoding))(functionuri,Somekey->Some(uri,key)|_,None->None)(fun(uri,key)->(uri,Somekey));]end)typesk_uri=Uri.tletmake_sk_uri(x:Uri.t):sk_uritzresultLwt.t=letopenLwt_result_syntaxinmatchUri.schemexwith|None->failwith"Error while parsing URI: AGGREGATE_SK_URI needs a scheme"|Some_->returnxmoduleSecret_key=Client_aliases.Alias(structletname="Aggregate_secret_key"typet=sk_uriincludeCompareUriletencoding=uri_encodingletof_sources=make_sk_uri@@Uri.of_stringsletto_sourcet=Lwt_result_syntax.return(Uri.to_stringt)end)endmoduletypeCOMMON_SIGNER=sigvalscheme:stringvaltitle:stringvaldescription:stringtypepk_uri=privateUri.ttypesk_uri=privateUri.ttypepublic_key_hashtypepublic_keytypesecret_keytypesignaturevalneuterize:sk_uri->pk_uritzresultLwt.tvalimport_secret_key:io:Client_context.io_wallet->pk_uri->(public_key_hash*public_keyoption)tzresultLwt.tvalpublic_key:pk_uri->public_keytzresultLwt.tvalpublic_key_hash:pk_uri->(public_key_hash*public_keyoption)tzresultLwt.tendmoduletypeAGGREGATE_SIGNER=sigincludeCOMMON_SIGNERwithtypepublic_key_hash=Tezos_crypto.Aggregate_signature.Public_key_hash.tandtypepublic_key=Tezos_crypto.Aggregate_signature.Public_key.tandtypesecret_key=Tezos_crypto.Aggregate_signature.Secret_key.tandtypepk_uri=aggregate_pk_uriandtypesk_uri=aggregate_sk_urivalsign:aggregate_sk_uri->Bytes.t->Tezos_crypto.Aggregate_signature.ttzresultLwt.tendmoduleMake_common_type(S:sigincludeTezos_crypto.Intfs.COMMON_SIGNATUREtypepk_uritypesk_uriend)=structtypepk_uri=S.pk_uritypesk_uri=S.sk_uritypepublic_key_hash=S.Public_key_hash.ttypepublic_key=S.Public_key.ttypesecret_key=S.Secret_key.ttypesignature=S.tendmoduleAggregate_type=Make_common_type(structincludeTezos_crypto.Aggregate_signaturetypepk_uri=aggregate_pk_uritypesk_uri=aggregate_sk_uriend)moduletypeSignature_S=sigincludeTezos_crypto.Intfs.SIGNATUREwithtypewatermark=Tezos_crypto.Signature.watermarkvalconcat:Bytes.t->t->Bytes.tmoduleAdapter:sigvalpublic_key_hash:Tezos_crypto.Signature.Public_key_hash.t->Public_key_hash.ttzresultvalpublic_key:Tezos_crypto.Signature.Public_key.t->Public_key.ttzresultvalsignature:Tezos_crypto.Signature.t->ttzresultendendmoduletypeSIMPLE_SIGNER=sigincludeCOMMON_SIGNERwithtypepk_uri=pk_uriandtypesk_uri=sk_urivalsign:?watermark:Tezos_crypto.Signature.watermark->sk_uri->Bytes.t->signaturetzresultLwt.tvaldeterministic_nonce:sk_uri->Bytes.t->Bytes.ttzresultLwt.tvaldeterministic_nonce_hash:sk_uri->Bytes.t->Bytes.ttzresultLwt.tvalsupports_deterministic_nonces:sk_uri->booltzresultLwt.tendmoduletypeS=sigtypepublic_key_hashtypepublic_keytypesecret_keytypewatermarktypesignaturemoduleSignature_type:sigtypenonrecpublic_key_hash=public_key_hashtypenonrecpublic_key=public_keytypenonrecsecret_key=secret_keytypenonrecsignature=signaturetypenonrecpk_uri=pk_uritypenonrecsk_uri=sk_uriendmodulePublic_key_hash:Client_aliases.Aliaswithtypet=public_key_hashmodulePublic_key:Client_aliases.Aliaswithtypet=pk_uri*public_keyoptionmoduleSecret_key:Client_aliases.Aliaswithtypet=sk_urivalimport_secret_key:io:Client_context.io_wallet->pk_uri->(public_key_hash*public_keyoption)tzresultLwt.tvalpublic_key:pk_uri->public_keytzresultLwt.tvalpublic_key_hash:pk_uri->(public_key_hash*public_keyoption)tzresultLwt.tvalneuterize:sk_uri->pk_uritzresultLwt.tvalsign:#Client_context.wallet->?watermark:watermark->sk_uri->Bytes.t->signaturetzresultLwt.tvalappend:#Client_context.wallet->?watermark:watermark->sk_uri->Bytes.t->Bytes.ttzresultLwt.tvalcheck:?watermark:watermark->pk_uri->signature->Bytes.t->booltzresultLwt.tvaldeterministic_nonce:sk_uri->Bytes.t->Bytes.ttzresultLwt.tvaldeterministic_nonce_hash:sk_uri->Bytes.t->Bytes.ttzresultLwt.tvalsupports_deterministic_nonces:sk_uri->booltzresultLwt.tvalregister_key:#Client_context.wallet->?force:bool->public_key_hash*pk_uri*sk_uri->?public_key:public_key->string->unittzresultLwt.tvalregister_keys:#Client_context.wallet->(string*public_key_hash*public_key*pk_uri*sk_uri)list->unittzresultLwt.tvallist_keys:#Client_context.wallet->(string*public_key_hash*public_keyoption*sk_urioption)listtzresultLwt.tvalalias_keys:#Client_context.wallet->string->(public_key_hash*public_keyoption*sk_urioption)optiontzresultLwt.tvalget_key:#Client_context.wallet->public_key_hash->(string*public_key*sk_uri)tzresultLwt.tvalget_public_key:#Client_context.wallet->public_key_hash->(string*public_key)tzresultLwt.tvalget_keys:#Client_context.wallet->(string*public_key_hash*public_key*sk_uri)listtzresultLwt.tvalforce_switch:unit->(bool,'ctx)Tezos_clic.argendmoduletypeSIGNER=SIMPLE_SIGNERwithtypepublic_key_hash=Tezos_crypto.Signature.Public_key_hash.tandtypepublic_key=Tezos_crypto.Signature.Public_key.tandtypesecret_key=Tezos_crypto.Signature.Secret_key.tandtypesignature=Tezos_crypto.Signature.ttypesigner=|Simpleof(moduleSIGNER)|Aggregateof(moduleAGGREGATE_SIGNER)letsigners_table:signerString.Hashtbl.t=String.Hashtbl.create13letregister_signersigner=letmoduleSigner=(valsigner:SIGNER)inString.Hashtbl.replacesigners_tableSigner.scheme(Simplesigner)letregister_aggregate_signersigner=letmoduleSigner=(valsigner:AGGREGATE_SIGNER)inString.Hashtbl.replacesigners_tableSigner.scheme(Aggregatesigner)letregistered_signers():(string*signer)list=String.Hashtbl.fold(funkvacc->(k,v)::acc)signers_table[]letfind_signer_for_key~scheme:signertzresult=letopenResult_syntaxinmatchString.Hashtbl.findsigners_tableschemewith|None->tzfail(Unregistered_key_schemescheme)|Somesigner->returnsignerletfind_aggregate_signer_for_key~scheme=letopenResult_syntaxinlet*signer=find_signer_for_key~schemeinmatchsignerwith|Simple_signer->tzfail(Wrong_key_scheme("aggregate","standard"))|Aggregatesigner->returnsignerletwith_scheme_aggregate_signer(uri:Uri.t)(f:(moduleAGGREGATE_SIGNER)->'atzresultLwt.t):'atzresultLwt.t=letopenLwt_result_syntaxinmatchUri.schemeuriwith|None->tzfail@@Unexisting_schemeuri|Somescheme->let*?signer=find_aggregate_signer_for_key~schemeinfsignerletregister_aggregate_keycctxt?(force=false)(public_key_hash,pk_uri,sk_uri)?public_keyname=letopenLwt_result_syntaxinlet*()=Aggregate_alias.Public_key.add~forcecctxtname(pk_uri,public_key)inlet*()=Aggregate_alias.Secret_key.add~forcecctxtnamesk_uriinAggregate_alias.Public_key_hash.add~forcecctxtnamepublic_key_hashletaggregate_neuterize(sk_uri:sk_uri):pk_uritzresultLwt.t=with_scheme_aggregate_signersk_uri(fun(moduleSigner:AGGREGATE_SIGNER)->Signer.neuterizesk_uri)letaggregate_public_keypk_uri=with_scheme_aggregate_signerpk_uri(fun(moduleSigner:AGGREGATE_SIGNER)->Signer.public_keypk_uri)(* This function is used to chose between two aliases associated
to the same key hash; if we know the secret key for one of them
we take it, otherwise if we know the public key for one of them
we take it. *)letjoin_keyskeys1_optkeys2=match(keys1_opt,keys2)with|Some(_,Some_,None),(_,None,None)->keys1_opt|Some(_,_,Some_),_->keys1_opt|_->Somekeys2(* For efficiency, this function avoids loading the wallet, except for
the call to [Public_key.update]. Indeed the arguments [pkhs],
[pks], [sks] represent the already loaded list of public key
hashes, public keys, and secret keys. *)letraw_get_aggregate_key_aux(cctxt:#Client_context.wallet)pkhspksskspkh=letopenLwt_result_syntaxinletrev_find_alllistpkh=List.filter_map(fun(name,pkh')->ifTezos_crypto.Aggregate_signature.Public_key_hash.equalpkhpkh'thenSomenameelseNone)listinletnames=rev_find_allpkhspkhinlet*o=List.fold_left_es(funkeys_optname->letsk_uri_opt=List.assoc~equal:String.equalnamesksinlet*pk_opt=matchList.assoc~equal:String.equalnamepkswith|None->return_none|Some(_,Somepk)->return_somepk|Some(pk_uri,None)->let*pk=aggregate_public_keypk_uriinlet*()=Aggregate_alias.Public_key.updatecctxtname(pk_uri,Somepk)inreturn_somepkinreturn@@join_keyskeys_opt(name,pk_opt,sk_uri_opt))Nonenamesinmatchowith|None->failwith"no keys for the source contract %a"Tezos_crypto.Aggregate_signature.Public_key_hash.pppkh|Somekeys->returnkeysletraw_get_aggregate_key(cctxt:#Client_context.wallet)pkh=letopenLwt_result_syntaxinlet*pkhs=Aggregate_alias.Public_key_hash.loadcctxtinlet*pks=Aggregate_alias.Public_key.loadcctxtinlet*sks=Aggregate_alias.Secret_key.loadcctxtinraw_get_aggregate_key_auxcctxtpkhspksskspkhletlist_aggregate_keyscctxt=letopenLwt_result_syntaxinlet*pkhs=Aggregate_alias.Public_key_hash.loadcctxtinlet*pks=Aggregate_alias.Public_key.loadcctxtinlet*sks=Aggregate_alias.Secret_key.loadcctxtinList.map_es(fun(name,pkh)->let*!r=raw_get_aggregate_key_auxcctxtpkhspksskspkhinmatchrwith|Ok(_name,pk,sk_uri)->return(name,pkh,pk,sk_uri)|Error_->return(name,pkh,None,None))pkhsletimport_aggregate_secret_key~iopk_uri=with_scheme_aggregate_signerpk_uri(fun(moduleSigner:AGGREGATE_SIGNER)->Signer.import_secret_key~iopk_uri)letalias_aggregate_keyscctxtname=letopenLwt_result_syntaxinlet*pkh=Aggregate_alias.Public_key_hash.findcctxtnameinlet*!r=raw_get_aggregate_keycctxtpkhinmatchrwith|Ok(_name,pk,sk_uri)->return_some(pkh,pk,sk_uri)|Error_->return_noneletaggregate_signcctxtsk_uribuf=letopenLwt_result_syntaxinwith_scheme_aggregate_signersk_uri(fun(moduleSigner:AGGREGATE_SIGNER)->let*signature=Signer.signsk_uribufinlet*pk_uri=Signer.neuterizesk_uriinlet*pubkey=let*o=Aggregate_alias.Secret_key.rev_findcctxtsk_uriinmatchowith|None->aggregate_public_keypk_uri|Somename->(let*r=Aggregate_alias.Public_key.findcctxtnameinmatchrwith|_,None->let*pk=aggregate_public_keypk_uriinlet*()=Aggregate_alias.Public_key.updatecctxtname(pk_uri,Somepk)inreturnpk|_,Somepubkey->returnpubkey)inlet*()=fail_unless(Tezos_crypto.Aggregate_signature.checkpubkeysignaturebuf)(Signature_mismatchsk_uri)inreturnsignature)moduleMake(Signature:Signature_S):Swithtypepublic_key_hash:=Signature.Public_key_hash.tandtypepublic_key:=Signature.Public_key.tandtypesecret_key:=Signature.Secret_key.tandtypewatermark:=Signature.watermarkandtypesignature:=Signature.t=structmodulePublic_key_hash=structincludeClient_aliases.Alias(struct(* includes t, Compare, encoding *)includeSignature.Public_key_hashletof_sources=Lwt.return(Signature.Public_key_hash.of_b58checks)letto_sourcep=Lwt.return_ok(Signature.Public_key_hash.to_b58checkp)letname="public key hash"end)endmoduleSecret_key=Client_aliases.Alias(structletname="secret_key"typet=sk_uriinclude(CompareUri:Compare.Swithtypet:=t)letof_sources=Lwt.return(make_sk_uri@@Uri.of_strings)letto_sourcet=Lwt.return_ok(Uri.to_stringt)letencoding=uri_encodingend)modulePublic_key=Client_aliases.Alias(structletname="public_key"typet=pk_uri*Signature.Public_key.toptionincludeCompare.Make(structtypenonrect=tletcompare(apk,aso)(bpk,bso)=Compare.or_else(CompareUri.compareapkbpk)(fun()->Option.compareSignature.Public_key.compareasobso)end)letof_sources=letopenLwt_result_syntaxinlet*?pk_uri=make_pk_uri@@Uri.of_stringsinreturn(pk_uri,None)letto_source(t,_)=Lwt.return_ok(Uri.to_stringt)letencoding=letopenData_encodinginunion[caseJson_only~title:"Locator_only"uri_encoding(functionuri,None->Someuri|_,Some_->None)(funuri->(uri,None));caseJson_only~title:"Locator_and_full_key"(obj2(req"locator"uri_encoding)(req"key"Signature.Public_key.encoding))(functionuri,Somekey->Some(uri,key)|_,None->None)(fun(uri,key)->(uri,Somekey));]end)moduleSignature_type=Make_common_type(structincludeSignaturetypenonrecpk_uri=pk_uritypenonrecsk_uri=sk_uriend)moduletypeV_SIGNER=SIMPLE_SIGNERwithtypepublic_key_hash=Signature.Public_key_hash.tandtypepublic_key=Signature.Public_key.tandtypesecret_key=Signature.Secret_key.tandtypesignature=Signature.tmoduleAdapt(S:SIGNER):V_SIGNER=structletscheme=S.schemelettitle=S.titleletdescription=S.descriptiontypepk_uri=Uri.ttypesk_uri=Uri.ttypepublic_key_hash=Signature.Public_key_hash.ttypepublic_key=Signature.Public_key.ttypesecret_key=Signature.Secret_key.ttypesignature=Signature.tletneuterize=S.neuterizeletimport_secret_key~iosk=letopenLwt_result_syntaxinlet*pkh,pk=S.import_secret_key~ioskinlet*?pkh=Signature.Adapter.public_key_hashpkhinlet*?pk=Option.map_eSignature.Adapter.public_keypkinreturn(pkh,pk)letpublic_keypk=letopenLwt_result_syntaxinlet*pk=S.public_keypkinlet*?pk=Signature.Adapter.public_keypkinreturnpkletpublic_key_hashpk=letopenLwt_result_syntaxinlet*pkh,pk=S.public_key_hashpkinlet*?pkh=Signature.Adapter.public_key_hashpkhinlet*?pk=Option.map_eSignature.Adapter.public_keypkinreturn(pkh,pk)letsign?watermarkskmsg=letopenLwt_result_syntaxinlet*signature=S.sign?watermarkskmsginlet*?signature=Signature.Adapter.signaturesignatureinreturnsignatureletdeterministic_nonce=S.deterministic_nonceletdeterministic_nonce_hash=S.deterministic_nonce_hashletsupports_deterministic_nonces=S.supports_deterministic_noncesendletadapt_signer(moduleSigner:SIGNER)=letmoduleV_Signer=Adapt(Signer)in(moduleV_Signer:V_SIGNER)letwith_scheme_signer(uri:Uri.t)(f:signer->'atzresultLwt.t):'atzresultLwt.t=letopenLwt_result_syntaxinmatchUri.schemeuriwith|None->tzfail@@Unexisting_schemeuri|Somescheme->let*?signer=find_signer_for_key~schemeinfsignerletfind_simple_signer_for_key~scheme=letopenResult_syntaxinlet*signer=find_signer_for_key~schemeinmatchsignerwith|Simplesigner->return(adapt_signersigner)|Aggregate_signer->tzfail(Wrong_key_scheme("simple","aggregate"))letwith_scheme_simple_signer(uri:Uri.t)(f:(moduleV_SIGNER)->'atzresultLwt.t):'atzresultLwt.t=letopenLwt_result_syntaxinmatchUri.schemeuriwith|None->tzfail@@Unexisting_schemeuri|Somescheme->let*?signer=find_simple_signer_for_key~schemeinfsignerletneuterize(sk_uri:sk_uri):pk_uritzresultLwt.t=with_scheme_simple_signersk_uri(fun(moduleSigner)->Signer.neuterizesk_uri)letpublic_keypk_uri=with_scheme_simple_signerpk_uri(fun(moduleSigner)->Signer.public_keypk_uri)letpublic_key_hashpk_uri=with_scheme_simple_signerpk_uri(fun(moduleSigner)->Signer.public_key_hashpk_uri)letimport_secret_key~iopk_uri=with_scheme_simple_signerpk_uri(fun(moduleSigner)->Signer.import_secret_key~iopk_uri)letsigncctxt?watermarksk_uribuf=letopenLwt_result_syntaxinwith_scheme_simple_signersk_uri(fun(moduleSigner)->let*signature=Signer.sign?watermarksk_uribufinlet*pk_uri=Signer.neuterizesk_uriinlet*pubkey=let*o=Secret_key.rev_findcctxtsk_uriinmatchowith|None->public_keypk_uri|Somename->(let*r=Public_key.findcctxtnameinmatchrwith|_,None->let*pk=public_keypk_uriinlet*()=Public_key.updatecctxtname(pk_uri,Somepk)inreturnpk|_,Somepubkey->returnpubkey)inlet*()=fail_unless(Signature.check?watermarkpubkeysignaturebuf)(Signature_mismatchsk_uri)inreturnsignature)letappendcctxt?watermarklocbuf=letopenLwt_result_syntaxinlet+signature=signcctxt?watermarklocbufinSignature.concatbufsignatureletcheck?watermarkpk_urisignaturebuf=letopenLwt_result_syntaxinlet*pk=public_keypk_uriinreturn(Signature.check?watermarkpksignaturebuf)letdeterministic_noncesk_uridata=with_scheme_simple_signersk_uri(fun(moduleSigner)->Signer.deterministic_noncesk_uridata)letdeterministic_nonce_hashsk_uridata=with_scheme_simple_signersk_uri(fun(moduleSigner)->Signer.deterministic_nonce_hashsk_uridata)letsupports_deterministic_noncessk_uri=letopenLwt_result_syntaxinwith_scheme_signersk_uri(function|Simple(moduleSigner:SIGNER)->Signer.supports_deterministic_noncessk_uri|Aggregate_->return_false)letregister_keycctxt?(force=false)(public_key_hash,pk_uri,sk_uri)?public_keyname=letopenLwt_result_syntaxinlet*()=Public_key.add~forcecctxtname(pk_uri,public_key)inlet*()=Secret_key.add~forcecctxtnamesk_uriinPublic_key_hash.add~forcecctxtnamepublic_key_hashletregister_keyscctxtxs=letopenLwt_result_syntaxinlet*()=Public_key.add_manycctxt(List.map(fun(name,_,pk,pk_uri,_)->(name,(pk_uri,Somepk)))xs)inlet*()=Secret_key.add_manycctxt(List.map(fun(name,_,_,_,sk_uri)->(name,sk_uri))xs)inlet*()=Public_key_hash.add_manycctxt(List.map(fun(name,public_key_hash,_,_,_)->(name,public_key_hash))xs)inreturn_unit(* For efficiency, this function avoids loading the wallet, except for
the call to [Public_key.update]. Indeed the arguments [pkhs],
[pks], [sks] represent the already loaded list of public key
hashes, public keys, and secret keys. *)letraw_get_key_aux(cctxt:#Client_context.wallet)pkhspksskspkh=letopenLwt_result_syntaxinletrev_find_alllistpkh=List.filter_map(fun(name,pkh')->ifSignature.Public_key_hash.equalpkhpkh'thenSomenameelseNone)listinlet*!r=letnames=rev_find_allpkhspkhinlet*o=List.fold_left_es(funkeys_optname->letsk_uri_opt=List.assoc~equal:String.equalnamesksinlet*pk_opt=matchList.assoc~equal:String.equalnamepkswith|None->return_none|Some(_,Somepk)->return_somepk|Some(pk_uri,None)->let*pk=public_keypk_uriinlet*()=Public_key.updatecctxtname(pk_uri,Somepk)inreturn_somepkinreturn@@join_keyskeys_opt(name,pk_opt,sk_uri_opt))Nonenamesinmatchowith|None->failwith"no keys for the source contract %a"Signature.Public_key_hash.pppkh|Somekeys->returnkeysinmatchrwith|(Ok(_,_,None)|Error_)asinitial_result->((* try to lookup for a remote key *)let*!r=let*?signer=find_simple_signer_for_key~scheme:"remote"inletmoduleSigner=(valsigner)inletpath=Signature.Public_key_hash.to_b58checkpkhinleturi=Uri.make~scheme:Signer.scheme~path()inlet*pk=Signer.public_keyuriinreturn(path,Somepk,Someuri)inmatchrwith|Error_->Lwt.returninitial_result|Ok_assuccess->Lwt.returnsuccess)|Ok_assuccess->Lwt.returnsuccessletraw_get_key(cctxt:#Client_context.wallet)pkh=letopenLwt_result_syntaxinlet*pkhs=Public_key_hash.loadcctxtinlet*pks=Public_key.loadcctxtinlet*sks=Secret_key.loadcctxtinraw_get_key_auxcctxtpkhspksskspkhletget_keycctxtpkh=letopenLwt_result_syntaxinlet*r=raw_get_keycctxtpkhinmatchrwith|pkh,Somepk,Somesk->return(pkh,pk,sk)|_pkh,_pk,None->failwith"Unknown secret key for %a"Signature.Public_key_hash.pppkh|_pkh,None,_sk->failwith"Unknown public key for %a"Signature.Public_key_hash.pppkhletget_public_keycctxtpkh=letopenLwt_result_syntaxinlet*r=raw_get_keycctxtpkhinmatchrwith|pkh,Somepk,_sk->return(pkh,pk)|_pkh,None,_sk->failwith"Unknown public key for %a"Signature.Public_key_hash.pppkhletget_keys(cctxt:#Client_context.wallet)=letopenLwt_result_syntaxinlet*sks=Secret_key.loadcctxtinlet*pkhs=Public_key_hash.loadcctxtinlet*pks=Public_key.loadcctxtinlet*!keys=List.filter_map_s(fun(name,sk_uri)->let*!r=matchList.assoc~equal:String.equalnamepkhswith|Somepkh->let*pk=matchList.assoc~equal:String.equalnamepkswith|Some(_,Somepk)->returnpk|Some(pk_uri,None)->let*pk=public_keypk_uriinlet*()=Public_key.updatecctxtname(pk_uri,Somepk)inreturnpk|None->failwith"no public key alias named %s"nameinreturn(name,pkh,pk,sk_uri)|None->failwith"no public key hash alias named %s"nameinmatchrwithOkr->Lwt.return_somer|Error_->Lwt.return_none)sksinreturnkeysletlist_keyscctxt=letopenLwt_result_syntaxinlet*pkhs=Public_key_hash.loadcctxtinlet*pks=Public_key.loadcctxtinlet*sks=Secret_key.loadcctxtinList.map_es(fun(name,pkh)->let*!r=raw_get_key_auxcctxtpkhspksskspkhinmatchrwith|Ok(_name,pk,sk_uri)->return(name,pkh,pk,sk_uri)|Error_->return(name,pkh,None,None))pkhsletalias_keyscctxtname=letopenLwt_result_syntaxinlet*pkh=Public_key_hash.findcctxtnameinlet*!r=raw_get_keycctxtpkhinmatchrwith|Ok(_name,pk,sk_uri)->return_some(pkh,pk,sk_uri)|Error_->return_noneletforce_switch()=Tezos_clic.switch~long:"force"~short:'f'~doc:"overwrite existing keys"()endmoduleV0=Make(structincludeTezos_crypto.Signature.V0letgenerate_key=generate_key?algo:NonemoduleAdapter=structletpublic_key_hash:Tezos_crypto.Signature.Public_key_hash.t->Public_key_hash.ttzresult=letopenResult_syntaxinfunction|Bls_->tzfail(Exn(Failure"BLS public key hash not supported by V0"))|Ed25519k->return(Ed25519k:Public_key_hash.t)|Secp256k1k->return(Secp256k1k:Public_key_hash.t)|P256k->return(P256k:Public_key_hash.t)letpublic_key:Tezos_crypto.Signature.Public_key.t->Public_key.ttzresult=letopenResult_syntaxinfunction|Bls_->tzfail(Exn(Failure"BLS public key not supported by V0"))|Ed25519k->return(Ed25519k:Public_key.t)|Secp256k1k->return(Secp256k1k:Public_key.t)|P256k->return(P256k:Public_key.t)letsignature:Tezos_crypto.Signature.t->ttzresult=letopenResult_syntaxinfunction|Bls_->tzfail(Exn(Failure"BLS signature not supported by V0"))|Ed25519k->return(Ed25519k:t)|Secp256k1k->return(Secp256k1k:t)|P256k->return(P256k:t)|Unknownk->return(Unknownk:t)endend)moduleV1=Make(structincludeTezos_crypto.Signature.V1letgenerate_key=generate_key?algo:NonemoduleAdapter=structletidentityx=Okxletpublic_key_hash=identityletpublic_key=identityletsignature=identityendend)moduleV_latest=Make(structincludeTezos_crypto.Signature.V_latestletgenerate_key=generate_key?algo:NonemoduleAdapter=structletidentityx=Okxletpublic_key_hash=identityletpublic_key=identityletsignature=identityendend)includeV_latestmoduleMnemonic=structletnew_random=Bip39.of_entropy(Tezos_crypto.Hacl.Rand.gen32)letto_32_bytesmnemonic=letseed_64_to_seed_32(seed_64:bytes):bytes=assert(Bytes.lengthseed_64=64);letfirst_32=Bytes.subseed_64032inletsecond_32=Bytes.subseed_643232inletseed_32=Bytes.create32infori=0to31doBytes.setseed_32i(Char.chr(Char.code(Bytes.getfirst_32i)lxorChar.code(Bytes.getsecond_32i)))done;seed_32inseed_64_to_seed_32(Bip39.to_seedmnemonic)letwords_pp=Format.(pp_print_list~pp_sep:pp_print_spacepp_print_string)end