123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470openStdLabelsmoduleBA=structincludeBigarray.Array1letlength=size_in_bytesletreccompare_recabilen_alen_b=ifi=len_a&&i=len_bthen0elseifi=len_athen-1elseifi=len_bthen1elsematchChar.compare(getai)(getbi)with|0->compare_recab(i+1)len_alen_b|n->nletcompareab=compare_recab0(lengtha)(lengthb)letequalab=compareab=0letcreatelen=Bigarray.(createcharc_layoutlen)endtypebuffer=(char,Bigarray.int8_unsigned_elt,Bigarray.c_layout)Bigarray.Array1.tmoduleContext=structtypeflag=|Verify|Signtypetexternalflags:buffer->int="context_flags"externalcreate:int->t="context_create"externalclone:t->t="context_clone"externalrandomize:t->buffer->bool="context_randomize"[@@noalloc]externalget_16:buffer->int->int="%caml_bigstring_get16"[@@noalloc]letflags=letbuf=BA.create(3*2)inlet_=flagsbufinbufletint_of_flag=function|Verify->get_16flags2|Sign->get_16flags4letcreatea=List.fold_lefta~init:(get_16flags0)~f:(funaf->alor(int_of_flagf))|>createletrandomizectxbuf=ifBA.lengthbuf<>32theninvalid_arg"Context.randomize: input must be 32 bytes long";randomizectxbufendmoduleKey=structtypesecrettypepublictype_t=|Sk:buffer->secrett|Pk:buffer->publictletto_buffer:typea.at->buffer=function|Skk->k|Pkk->kletsecret_bytes=32letpublic_bytes=64letlength:typea.at->int=function|Sk_->32|Pk_->64letequal:typea.at->at->bool=funab->matcha,bwith|Ska,Skb->BA.equalab|Pka,Pkb->BA.equalabletcopy:typea.at->at=function|Skk->letk'=BA.createsecret_bytesinBA.blitkk';Skk'|Pkk->letk'=BA.createpublic_bytesinBA.blitkk';Pkk'externalsk_negate_inplace:Context.t->buffer->unit="ec_privkey_negate"[@@noalloc]externalsk_add_tweak_inplace:Context.t->buffer->buffer->bool="ec_privkey_tweak_add"[@@noalloc]externalsk_mul_tweak_inplace:Context.t->buffer->buffer->bool="ec_privkey_tweak_mul"[@@noalloc]externalpk_negate_inplace:Context.t->buffer->unit="ec_pubkey_negate"[@@noalloc]externalpk_add_tweak_inplace:Context.t->buffer->buffer->bool="ec_pubkey_tweak_add"[@@noalloc]externalpk_mul_tweak_inplace:Context.t->buffer->buffer->bool="ec_pubkey_tweak_mul"[@@noalloc]externalpk_combine:Context.t->buffer->bufferlist->bool="ec_pubkey_combine"[@@noalloc]letnegate_inplace:typea.Context.t->at->unit=functx->function|Skk->sk_negate_inplacectxk|Pkk->pk_negate_inplacectxkletnegatectxk=letk'=copykinnegate_inplacectxk';k'letop_tweak:typea.string->(Context.t->buffer->buffer->bool)->Context.t->at->?pos:int->buffer->buffer=funnamefctxk?(pos=0)buf->letbuflen=BA.lengthbufinifpos<0||pos>buflen-32theninvalid_arg(Printf.sprintf"Key.%s: pos < 0 or pos > buflen - 32"name);letbuf=BA.subbufpos32inletk'=copyk|>to_bufferinifnot(fctxk'buf)thenfailwith(Printf.sprintf"Key.%s: operation failed"name);k'letadd_tweak:typea.Context.t->at->?pos:int->buffer->at=functxk?posbuf->matchkwith|Sk_->Sk(op_tweak"add_tweak"sk_add_tweak_inplacectxk?posbuf)|Pk_->Pk(op_tweak"add_tweak"pk_add_tweak_inplacectxk?posbuf)letmul_tweak:typea.Context.t->at->?pos:int->buffer->at=functxk?posbuf->matchkwith|Sk_->Sk(op_tweak"mul_tweak"sk_mul_tweak_inplacectxk?posbuf)|Pk_->Pk(op_tweak"mul_tweak"pk_mul_tweak_inplacectxk?posbuf)externalpk_parse:Context.t->buffer->buffer->bool="ec_pubkey_parse"[@@noalloc]externalpk_serialize:Context.t->buffer->buffer->int="ec_pubkey_serialize"[@@noalloc]externalpk_create:Context.t->buffer->buffer->bool="ec_pubkey_create"[@@noalloc]letneuterize:typea.Context.t->at->publictoption=functx->function|Pkpk->Some(Pkpk)|Sksk->letpk=BA.createpublic_bytesinifpk_createctxpkskthenSome(Pkpk)elseNoneletneuterize_exnctxk=matchneuterizectxkwith|None->invalid_arg"Key.neuterize_exn: invalid secret key"|Somepk->pkletlist_map_filter_opt~fl=List.fold_left~init:[]~f:beginfunae->matchfewith|None->a|Somer->r::aendlletcombinectxpks=letnb_pks=List.lengthpksinifnb_pks=0||nb_pks>1024thenNoneelseletpk=BA.createpublic_bytesinletpks=list_map_filter_opt~f:beginfunk->matchneuterizectxkwith|None->None|Some(Pkk)->Somekendpksinifpk_combinectxpkpksthenSome(Pkpk)elseNoneletcombine_exnctxpks=matchcombinectxpkswith|None->invalid_arg"Key.combine_exn: sum of pks is invalid"|Somepk->pkexternalverify_sk:Context.t->buffer->bool="ec_seckey_verify"[@@noalloc]letread_sk_exnctx?(pos=0)buf=letbuflen=BA.lengthbufinifpos<0||pos>buflen-secret_bytestheninvalid_arg"Key.read_sk: pos < 0 or pos + 32 > buflen";letbuf=BA.subbufpossecret_bytesinmatchverify_skctxbufwith|true->lett=BA.createsecret_bytesinBA.blitbuft;Skbuf|false->invalid_arg"Key.read_sk_exn: secret key is invalid"letread_skctx?posbuf=tryOk(read_sk_exnctxbuf)with|Invalid_argumentmsg->Errormsgletread_pk_exnctx?(pos=0)inbuf=letpklen=BA.lengthinbufinifpos<0||pos>pklen-33theninvalid_arg"Key.read_pk: pos < 0 or pos > buflen - 33";letinbuf=BA.(subinbufpos(lengthinbuf))inifBA.(lengthinbuf<33)theninvalid_arg"Key.read_pk: input must be at least 33 bytes long";letoutbuf=BA.createpublic_bytesinif(pk_parsectxoutbufinbuf)thenPkoutbufelseinvalid_arg"Key.read_pk_exn: public key is invalid"letread_pkctx?posbuf=tryOk(read_pk_exnctxbuf)with|Invalid_argumentmsg->Errormsgletwrite:typea.?compress:bool->Context.t->?pos:int->buffer->at->int=fun?(compress=true)ctx?(pos=0)buf->function|Sksk->letbuflen=BA.lengthbufinifpos<0||pos>buflen-secret_bytestheninvalid_arg"Key.write (secret): pos < 0 or pos + 32 > buflen";letbuf=BA.subbufpossecret_bytesinBA.blitskbuf;secret_bytes|Pkpk->letbuflen=BA.lengthbufinifpos<0||(compress&&pos>buflen-33)||(notcompress&&pos>buflen-65)theninvalid_arg(Printf.sprintf"Key.write (public): pos=%d, buflen=%d"posbuflen);letlen=ifcompressthen33else65inletbuf=BA.subbufposleninpk_serializectxbufpkletto_bytes:typea.?compress:bool->Context.t->at->buffer=fun?(compress=true)ctx->function|Sk_assk->letbuf=BA.createsecret_bytesinlet_=write~compressctxbufskinbuf|Pk_aspk->letbuf=BA.create(1+(ifcompressthensecret_byteselsepublic_bytes))inlet_=write~compressctxbufpkinbufendmoduleSign=structtypeplaintyperecoverabletype_t=|P:buffer->plaint|R:buffer->recoverabletletplain_bytes=64letrecoverable_bytes=65letmsg_bytes=32typemsg=bufferletmsg_of_bytes?(pos=0)buf=trySome(BA.subbufposmsg_bytes)with_->Noneletmsg_of_bytes_exn?posbuf=matchmsg_of_bytes?posbufwith|None->invalid_arg"msg_of_bytes_exn"|Somemsg->msgletwrite_msg_exn?(pos=0)bufmsg=letbuflen=BA.lengthbufinifpos<0||pos>buflen-msg_bytestheninvalid_arg"Sign.read_exn: pos < 0 or pos > buflen - 64";BA.blit(BA.submsg0msg_bytes)(BA.subbufposmsg_bytes);msg_bytesletwrite_msg?posbufmsg=tryOk(write_msg_exn?posbufmsg)with|Invalid_argumentmsg->Errormsgletmsg_to_bytesmsg=msgletequal:typea.at->at->bool=funab->matcha,bwith|Pa,Pb->BA.equalab|Ra,Rb->BA.equalabexternalparse_compact:Context.t->buffer->buffer->bool="ecdsa_signature_parse_compact"[@@noalloc]externalparse_der:Context.t->buffer->buffer->bool="ecdsa_signature_parse_der"[@@noalloc]externalserialize_compact:Context.t->buffer->buffer->unit="ecdsa_signature_serialize_compact"[@@noalloc]externalserialize_der:Context.t->buffer->buffer->int="ecdsa_signature_serialize_der"[@@noalloc]externalparse_recoverable:Context.t->buffer->buffer->int->bool="ecdsa_recoverable_signature_parse_compact"[@@noalloc]externalserialize_recoverable:Context.t->buffer->buffer->int="ecdsa_recoverable_signature_serialize_compact"[@@noalloc]letread_exnctx?(pos=0)buf=letbuflen=BA.lengthbufinifpos<0||pos>buflen-plain_bytestheninvalid_arg"Sign.read_exn: pos < 0 or pos > buflen - 64";letsignature=BA.createplain_bytesinifparse_compactctxsignature(BA.subbufposplain_bytes)thenPsignatureelseinvalid_arg"Sign.read_exn: signature could not be parsed"letreadctx?posbuf=tryOk(read_exnctxbuf)with|Invalid_argumentmsg->Errormsgletread_der_exnctx?(pos=0)buf=letbuflen=BA.lengthbufinifpos<0||pos>buflen-plain_bytestheninvalid_arg"Sign.read_der: pos < 0 or pos > buflen - 72";letsignature=BA.createplain_bytesinifparse_derctxsignatureBA.(subbufpos(lengthbuf))thenPsignatureelseinvalid_arg"Sign.read_der_exn: signature could not be parsed"letread_derctx?posbuf=tryOk(read_der_exnctxbuf)with|Invalid_argumentmsg->Errormsgletread_recoverable_exnctx~recid?(pos=0)buf=letbuflen=BA.lengthbufinifpos<0||pos>buflen-plain_bytestheninvalid_arg"Sign.read_recoverable_exn: pos < 0 or pos > buflen - 64";letsignature=BA.createrecoverable_bytesinifparse_recoverablectxsignature(BA.subbufposplain_bytes)recidthen(Rsignature)elseinvalid_arg"Sign.read_recoverable_exn: signature could not be parsed"letread_recoverablectx~recid?posbuf=tryOk(read_recoverable_exnctx~recid?posbuf)with|Invalid_argumentmsg->Errormsgletwrite_exn:typea.?der:bool->Context.t->?pos:int->buffer->at->int=fun?(der=false)ctx?(pos=0)buf->function|Psignature->letbuf=BA.(subbufpos(lengthbuf))inifderthenserialize_derctxbufsignatureelse(serialize_compactctxbufsignature;plain_bytes)|Rsignature->letbuflen=BA.lengthbufinifpos<0||pos>buflen-plain_bytestheninvalid_arg"write: pos < 0 or pos > buflen - 64";ignore(serialize_recoverablectx(BA.subbufposplain_bytes)signature);plain_bytesletwrite?derctx?posbufsignature=tryOk(write_exn?derctx?posbufsignature)with|Invalid_argumentmsg->Errormsgletto_bytes?derctxsignature=letbuf=BA.create72inletnb_written=write_exn?derctxbufsignatureinBA.subbuf0nb_writtenletto_bytes_recidctx(Rsignature)=letbuf=BA.createplain_bytesinletrecid=serialize_recoverablectxbufsignatureinbuf,recidexternalsign:Context.t->buffer->buffer->buffer->bool="ecdsa_sign"[@@noalloc]externalverify:Context.t->buffer->buffer->buffer->bool="ecdsa_verify"[@@noalloc]letwrite_sign_exnctx~sk~msg?(pos=0)buf=letbuflen=BA.lengthbufinifpos<0||pos>buflen-plain_bytestheninvalid_arg"Sign.write_sign: outpos < 0 or outpos > outbuf - 64";ifsignctx(BA.subbufposplain_bytes)(Key.to_buffersk)msgthenplain_byteselseinvalid_arg"Sign.write_sign: the nonce generation function failed, or the private key was invalid"letwrite_signctx~sk~msg?posbuf=tryOk(write_sign_exnctx~sk~msg?posbuf)with|Invalid_argumentmsg->Errormsgletsignctx~sk~msg=letsignature=BA.createplain_bytesinmatchwrite_signctx~sk~msgsignaturewith|Errormsg->Errormsg|Ok_nb_written->Ok(Psignature)letsign_exnctx~sk~msg=matchsignctx~sk~msgwith|Errormsg->invalid_argmsg|Oksignature->signatureexternalsign_recoverable:Context.t->buffer->buffer->buffer->bool="ecdsa_sign_recoverable"[@@noalloc]letwrite_sign_recoverable_exnctx~sk~msg?(pos=0)buf=letbuflen=BA.lengthbufinifpos<0||pos>buflen-recoverable_bytestheninvalid_arg"Sign.write_sign_recoverable_exn: \
outpos < 0 or outpos > outbuflen - 65";ifsign_recoverablectx(BA.subbufposrecoverable_bytes)(Key.to_buffersk)msgthenrecoverable_byteselseinvalid_arg"Sign.write_sign_recoverable_exn: \
the nonce generation function failed, or the private key was invalid"letwrite_sign_recoverablectx~sk~msg?posbuf=tryOk(write_sign_recoverable_exnctx~sk~msg?posbuf)with|Invalid_argumentmsg->Errormsgletsign_recoverablectx~skmsg=letsignature=BA.createrecoverable_bytesinmatchwrite_sign_recoverablectx~sk~msgsignaturewith|Errorerror->Errorerror|Ok_nb_written->Ok(Rsignature)letsign_recoverable_exnctx~skmsg=matchsign_recoverablectx~skmsgwith|Errormsg->invalid_argmsg|Oksignature->signatureexternalto_plain:Context.t->buffer->buffer->unit="ecdsa_recoverable_signature_convert"[@@noalloc]letto_plainctx(Rrecoverable)=letplain=BA.createplain_bytesinto_plainctxplainrecoverable;Pplainletverify_plain_exnctx~pk?(pos=0)msgsignature=letmsglen=BA.lengthmsginifpos<0||pos>msglen-32theninvalid_arg"Sign.verify: msg must be at least 32 bytes long";verifyctx(Key.to_bufferpk)(BA.submsgpos32)signatureletverify_exn:typea.Context.t->pk:Key.publicKey.t->msg:msg->signature:at->bool=functx~pk~msg~signature->matchsignaturewith|Psignature->verify_plain_exnctx~pkmsgsignature|Rsignatureasr->letPsignature=to_plainctxrinverify_plain_exnctx~pkmsgsignatureletverifyctx~pk~msg~signature=tryOk(verify_exnctx~pk~msg~signature)with|Invalid_argumentmsg->Errormsgexternalrecover:Context.t->buffer->buffer->buffer->bool="ecdsa_recover"[@@noalloc]letrecover_exnctx~signature:(Rsignature)~msg=letpk=BA.createKey.public_bytesinifrecoverctxpksignaturemsgthenKey.Pkpkelseinvalid_arg"Sign.recover: pk could not be recovered"letrecoverctx~signature~msg=tryOk(recover_exnctx~signature~msg)with|Invalid_argumentmsg->Errormsgend