123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219(*****************************************************************************)(* *)(* 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. *)(* *)(*****************************************************************************)(** Tezos - X25519/XSalsa20-Poly1305 cryptography *)openHacltypesecret_key=secretBox.keytypepublic_key=publicBox.keytypechannel_key=Box.combinedBox.keytypenonce=Bytes.ttypepow_target=Z.tmoduleSecretbox=structincludeHacl.Secretboxletsecretboxkeymsgnonce=letmsglen=Bytes.lengthmsginletcmsg=Bytes.create(msglen+tagbytes)insecretbox~key~nonce~msg~cmsg;cmsgletsecretbox_openkeycmsgnonce=letcmsglen=Bytes.lengthcmsginletmsg=Bytes.create(cmsglen-tagbytes)inmatchsecretbox_open~key~nonce~cmsg~msgwith|false->None|true->SomemsgendmodulePublic_key_hash=Blake2B.Make(Base58)(structletname="Crypto_box.Public_key_hash"lettitle="A Cryptobox public key ID"letb58check_prefix=Base58.Prefix.cryptobox_public_key_hashletsize=Some16end)let()=Base58.check_encoded_prefixPublic_key_hash.b58check_encoding"id"30lethashpk=Public_key_hash.hash_bytes[Box.unsafe_to_bytespk]lettag_length=Box.tagbytesletrandom_keypair()=let(pk,sk)=Box.keypair()in(sk,pk,hashpk)letzero_nonce=Bytes.makeNonce.size'\x00'letrandom_nonce=Nonce.genletincrement_nonce=Nonce.incrementletgenerate_noncebytes_list=lethash=Blake2B.hash_bytesbytes_listinlets=Blake2B.to_byteshashinNonce.of_bytes_exn@@Bytes.subs0Nonce.sizeletinit_to_resp_seed=Bytes.of_string"Init -> Resp"letresp_to_init_seed=Bytes.of_string"Resp -> Init"letgenerate_nonces~incoming~sent_msg~recv_msg=let((init_msg,resp_msg,false)|(resp_msg,init_msg,true))=(sent_msg,recv_msg,incoming)inletnonce_init_to_resp=generate_nonce[init_msg;resp_msg;init_to_resp_seed]inletnonce_resp_to_init=generate_nonce[init_msg;resp_msg;resp_to_init_seed]inifincomingthen(nonce_init_to_resp,nonce_resp_to_init)else(nonce_resp_to_init,nonce_init_to_resp)letprecomputeskpk=Box.dhpkskletfast_box_noallocknoncetagbuf=Box.box_noalloc~k~nonce~buf~tagletfast_box_open_noallocknoncetagbuf=Box.box_open_noalloc~k~nonce~buf~tagletfast_boxknoncemsg=letcmsg=Bytes.create(Bytes.lengthmsg+tag_length)inBox.box~k~nonce~msg~cmsg;cmsgletfast_box_openknoncecmsg=letcmsglen=Bytes.lengthcmsginassert(cmsglen>=tag_length);letmsg=Bytes.create(cmsglen-tag_length)inifBox.box_open~k~nonce~cmsg~msgthenSomemsgelseNoneletcompare_pow_targethashpow_target=lethash=Z.of_bits(Blake2B.to_stringhash)inZ.comparehashpow_target<=0letmake_pow_targetf=iff<0.||256.<ftheninvalid_arg"Cryptobox.target_of_float";let(frac,shift)=modffinletshift=int_of_floatshiftinletm=Z.of_int64@@iffrac=0.thenInt64.(pred(shift_left1L54))elseInt64.of_float(2.**(54.-.frac))inifshift<202thenZ.logor(Z.shift_leftm(202-shift))(Z.pred@@Z.shift_leftZ.one(202-shift))elseZ.shift_rightm(shift-202)letdefault_pow_target=make_pow_target24.lettarget_0=make_pow_target0.letcheck_proof_of_workpknoncepow_target=lethash=Blake2B.hash_bytes[Box.unsafe_to_bytespk;nonce]incompare_pow_targethashpow_target(* This is the non-yielding function to generate an identity. It performs a
bounded number of attempts ([n]). This function is not exported. Instead, the
wrapper below, [generate_proof_of_work], uses this function repeatedly but it
intersperses calls to [Lwt.pause] to yield explicitly. *)letgenerate_proof_of_work_n_attemptsnpkpow_target=letrecloopnonceattempts=ifattempts>nthenraiseNot_foundelseifcheck_proof_of_workpknoncepow_targetthennonceelseloop(Nonce.incrementnonce)(attempts+1)inloop(random_nonce())0letgenerate_proof_of_work_with_target_0pk=generate_proof_of_work_n_attempts1pktarget_0letrecgenerate_proof_of_work?(yield_every=10000)?maxpkpow_target=letopenLwt.Infixinmatchmaxwith|None->(tryletpow=generate_proof_of_work_n_attemptsyield_everypkpow_targetinLwt.returnpowwithNot_found->Lwt.pause()>>=fun()->generate_proof_of_work~yield_everypkpow_target)|Somemax->(ifmax<=0thenLwt.applyraiseNot_foundelseletattempts=minmaxyield_everyintryletpow=generate_proof_of_work_n_attemptsattemptspkpow_targetinLwt.returnpowwithNot_found->Lwt.pause()>>=fun()->letmax=max-attemptsingenerate_proof_of_work~yield_every~maxpkpow_target)letpublic_key_to_bytespk=Bytes.copy(Box.unsafe_to_bytespk)letpublic_key_of_bytesbuf=Box.unsafe_pk_of_bytes(Bytes.copybuf)letpublic_key_size=Box.pkbytesletsecret_key_to_bytessk=Bytes.copy(Box.unsafe_to_bytessk)letsecret_key_of_bytesbuf=Box.unsafe_sk_of_bytes(Bytes.copybuf)letsecret_key_size=Box.skbytesletnonce_size=Nonce.sizeletpublic_key_encoding=letopenData_encodinginconvpublic_key_to_bytespublic_key_of_bytes(Fixed.bytespublic_key_size)letsecret_key_encoding=letopenData_encodinginconvsecret_key_to_bytessecret_key_of_bytes(Fixed.bytessecret_key_size)letnonce_encoding=Fixed.bytesnonce_sizeletneuterize:secret_key->public_key=Box.neuterizeletequal:public_key->public_key->bool=Box.equalletpp_pkppfpk=Hex.ppppf(Hex.of_bytes(public_key_to_bytespk))