123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2020 Nomadic Labs <contact@nomadic-labs.com> *)(* Copyright (c) 2020 Metastate AG <hello@metastate.dev> *)(* *)(* 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. *)(* *)(*****************************************************************************)typesecret_key=Unencryptedofstring|Encryptedofstringtypekey={alias:string;public_key_hash:string;public_key:string;secret_key:secret_key;}typeaggregate_key={aggregate_alias:string;aggregate_public_key_hash:string;aggregate_public_key:string;aggregate_secret_key:secret_key;}letrequire_unencrypted_secret_key~__LOC__=function|Unencryptedb58_secret_key->b58_secret_key|Encrypted_->Test.fail~__LOC__"[require_unencrypted_secret_key] expected an unencrypted secret key"letsign_bytes~watermark~(signer:key)(message:Bytes.t)=letb58_secret_key=require_unencrypted_secret_key~__LOC__signer.secret_keyinletsecret_key=Tezos_crypto.Signature.Secret_key.of_b58check_exnb58_secret_keyinTezos_crypto.Signature.sign~watermarksecret_keymessageleturi_of_secret_key=function|Unencryptedsecret_key->"unencrypted:"^secret_key|Encryptedsecret_key->"encrypted:"^secret_keyletsecret_key_equalsecret_key1secret_key2=match(secret_key1,secret_key2)with|Unencrypteds1,Unencrypteds2|Encrypteds1,Encrypteds2->String.equals1s2|_->falseletsecret_key_typ:secret_keyCheck.typ=Check.equalable(funfmtsecret_key->Format.fprintffmt"%s"(uri_of_secret_keysecret_key))(funsecret_key1secret_key2->secret_key_equalsecret_key1secret_key2)letkey_typ:keyCheck.typ=Check.equalable(funfmt{alias;public_key_hash;public_key;secret_key}->Format.fprintffmt"{alias: %S; public_key_hash: %S; public_key: %s; secret_key: %S}"aliaspublic_key_hashpublic_key(uri_of_secret_keysecret_key))(funkey1key2->String.equalkey1.aliaskey2.alias&&String.equalkey1.public_key_hashkey2.public_key_hash&&String.equalkey1.public_keykey2.public_key&&secret_key_equalkey1.secret_keykey2.secret_key)moduleWallet:sigvalwrite:keylist->base_dir:string->unitend=structletpath_of_kind=function|`Public_key_hash->"public_key_hashs"|`Public_key->"public_keys"|`Secret_key->"secret_keys"letjson_of_secret_keysecret_key=`String(uri_of_secret_keysecret_key)letjson_of_public_keypublic_key=`String("unencrypted:"^public_key)letjson_of_kindkey=letmk_objvalue=`O[("name",`Stringkey.alias);("value",value)]infunction|`Public_key_hash->mk_obj@@`Stringkey.public_key_hash|`Public_key->mk_obj@@json_of_public_keykey.public_key|`Secret_key->mk_obj@@json_of_secret_keykey.secret_keyletwrite_kindwallet~base_dirkind=letfilename=base_dir//path_of_kindkindinletjson=`A(List.map(funx->json_of_kindxkind)wallet)inJSON.encode_to_file_ufilenamejsonletwritewallet~base_dir=List.iter(funkind->write_kindwallet~base_dirkind)[`Public_key_hash;`Public_key;`Secret_key]endletwrite=Wallet.writemoduleBootstrap=structletaliasn="bootstrap"^string_of_intnletkeys=[|{alias="bootstrap1";public_key_hash="tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx";public_key="edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav";secret_key=Unencrypted"edsk3gUfUPyBSfrS9CCgmCiQsTCHGkviBDusMxDJstFtojtc1zcpsh";};{alias="bootstrap2";public_key_hash="tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN";public_key="edpktzNbDAUjUk697W7gYg2CRuBQjyPxbEg8dLccYYwKSKvkPvjtV9";secret_key=Unencrypted"edsk39qAm1fiMjgmPkw1EgQYkMzkJezLNewd7PLNHTkr6w9XA2zdfo";};{alias="bootstrap3";public_key_hash="tz1faswCTDciRzE4oJ9jn2Vm2dvjeyA9fUzU";public_key="edpkuTXkJDGcFd5nh6VvMz8phXxU3Bi7h6hqgywNFi1vZTfQNnS1RV";secret_key=Unencrypted"edsk4ArLQgBTLWG5FJmnGnT689VKoqhXwmDPBuGx3z4cvwU9MmrPZZ";};{alias="bootstrap4";public_key_hash="tz1b7tUupMgCNw2cCLpKTkSD1NZzB5TkP2sv";public_key="edpkuFrRoDSEbJYgxRtLx2ps82UdaYc1WwfS9sE11yhauZt5DgCHbU";secret_key=Unencrypted"edsk2uqQB9AY4FvioK2YMdfmyMrer5R8mGFyuaLLFfSRo8EoyNdht3";};{alias="bootstrap5";public_key_hash="tz1ddb9NMYHZi5UzPdzTZMYQQZoMub195zgv";public_key="edpkv8EUUH68jmo3f7Um5PezmfGrRF24gnfLpH3sVNwJnV5bVCxL2n";secret_key=Unencrypted"edsk4QLrcijEffxV31gGdN2HU7UpyJjA8drFoNcmnB28n89YjPNRFm";};|]endletparse_client_output_public_keys~client_output=letpublic_key_hash=(* group of letters and digits after "Hash: "
e.g. "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" *)client_output=~*rex"Hash: ?(\\w*)"|>mandatory"public key hash"inletpublic_key=(* group of letters and digits after "Public Key: "
e.g. "edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" *)client_output=~*rex"Public Key: ?(\\w*)"|>mandatory"public key"in(public_key_hash,public_key)letparse_client_output~alias~client_output=letpublic_key_hash,public_key=parse_client_output_public_keys~client_outputinletsecret_key=(* group of letters and digits after "Secret Key: (un)encrypted:" e.g.
"edsk3gUfUPyBSfrS9CCgmCiQsTCHGkviBDusMxDJstFtojtc1zcpsh". *)matchclient_output=~**rex"Secret Key: ?(\\w*):?(\\w*)"with|Some("unencrypted",sk)->Unencryptedsk|Some("encrypted",sk)->Encryptedsk|_->Test.fail"Could not parse [show address] output: %s"client_outputin{alias;public_key_hash;public_key;secret_key}letparse_client_output_aggregate~alias~client_output=letaggregate_public_key_hash,aggregate_public_key=parse_client_output_public_keys~client_outputinletaggregate_secret_key=(* group of letters and digits after "Secret Key: aggregate_unencrypted"
e.g. "BLsk1hKAHyGqY9qRbgoSVnjiSmDWpKGjFF3WNQ7BaiaMUA6RMA6Pfq" Note: The
tests only use unencrypted keys for the moment. If this changes, please
update secret key parsing. *)client_output=~*rex"Secret Key: aggregate_unencrypted:?(\\w*)"|>mandatory"secret key"|>funsk->Unencryptedskin{aggregate_alias=alias;aggregate_public_key_hash;aggregate_public_key;aggregate_secret_key;}