123456789101112131415161718192021222324252627282930313233343536373839404142moduletypeS=sigvalextract:?salt:string->string->stringvalexpand:prk:string->?info:string->int->stringendmoduleMake(H:Digestif.S):S=structletextract?saltikm=letkey=matchsaltwith|None->String.makeH.digest_size'\x00'|Somex->xinH.(to_raw_string(hmac_string~keyikm))letexpand~prk?infolen=letinfo=matchinfowith|None->""|Somex->xinlettnlast=letnc=String.make1(Char.unsafe_chrn)inH.(to_raw_string(hmac_string~key:prk(String.concat""[last;info;nc])))inletn=succ(len/H.digest_size)inletreccomputeacccount=matchcount,accwith|c,xswhenc>n->String.concat""(List.revxs)|c,x::_->compute(tcx::acc)(succc)|_,[]->invalid_arg"can not happen"inletbuf=compute[""]1inString.subbuf0lenendletextract~hash?saltikm=letmoduleH=(val(Digestif.module_of_hash'hash))inletmoduleHKDF=Make(H)inHKDF.extract?saltikmletexpand~hash~prk?infolen=letmoduleH=(val(Digestif.module_of_hash'hash))inletmoduleHKDF=Make(H)inHKDF.expand~prk?infolen