123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187moduleBy=Digestif_bymoduleBi=Digestif_biletnist_padding=0x06Lletkeccak_padding=0x01LmoduleInt64=structincludeInt64let(lsl)=Int64.shift_leftlet(lsr)=Int64.shift_right_logicallet(asr)=Int64.shift_rightlet(lor)=Int64.logorlet(land)=Int64.logandlet(lxor)=Int64.logxorlet(+)=Int64.addletror64an=(alsrn)lor(alsl(64-n))letrol64an=(alsln)lor(alsr(64-n))endmoduleUnsafe(P:sigvalpadding:int64end)=structtypectx={q:int64array;rsize:int;(* block size *)mdlen:int;(* output size *)mutablept:int;}letdupctx={q=Array.copyctx.q;rsize=ctx.rsize;mdlen=ctx.mdlen;pt=ctx.pt}letinitmdlen=letrsize=200-(2*mdlen)in{q=Array.make250L;rsize;mdlen;pt=0}letkeccakf_rounds=24letkeccaft_rndc:int64array=[|0x0000000000000001L;0x0000000000008082L;0x800000000000808aL;0x8000000080008000L;0x000000000000808bL;0x0000000080000001L;0x8000000080008081L;0x8000000000008009L;0x000000000000008aL;0x0000000000000088L;0x0000000080008009L;0x000000008000000aL;0x000000008000808bL;0x800000000000008bL;0x8000000000008089L;0x8000000000008003L;0x8000000000008002L;0x8000000000000080L;0x000000000000800aL;0x800000008000000aL;0x8000000080008081L;0x8000000000008080L;0x0000000080000001L;0x8000000080008008L;|]letkeccaft_rotc:intarray=[|1;3;6;10;15;21;28;36;45;55;2;14;27;41;56;8;25;43;62;18;39;61;20;44;|]letkeccakf_piln:intarray=[|10;7;11;17;18;3;5;16;8;21;24;4;15;23;19;13;12;2;20;14;22;9;6;1;|]letsha3_keccakf(q:int64array)=forr=0tokeccakf_rounds-1dolet(lxor)=Int64.(lxor)inletlnot=Int64.lognotinlet(land)=Int64.(land)in(* Theta *)letbc=Array.init5(funi->q.(i)lxorq.(i+5)lxorq.(i+10)lxorq.(i+15)lxorq.(i+20))infori=0to4dolett=bc.((i+4)mod5)lxorInt64.rol64bc.((i+1)mod5)1infork=0to4doletj=k*5inq.(j+i)<-q.(j+i)lxortdonedone;(* Rho Pi *)lett=refq.(1)inlet_=Array.iteri(funirotc->letj=keccakf_piln.(i)inbc.(0)<-q.(j);q.(j)<-Int64.rol64!trotc;t:=bc.(0))keccaft_rotcin(* Chi *)fork=0to4doletj=k*5inletbc=Array.init5(funi->q.(j+i))infori=0to4doq.(j+i)<-q.(j+i)lxor(lnotbc.((i+1)mod5)landbc.((i+2)mod5))donedone;(* Iota *)q.(0)<-q.(0)lxorkeccaft_rndc.(r)doneletmasks=[|0xffffffffffffff00L;0xffffffffffff00ffL;0xffffffffff00ffffL;0xffffffff00ffffffL;0xffffff00ffffffffL;0xffff00ffffffffffL;0xff00ffffffffffffL;0x00ffffffffffffffL;|]letfeed:typea.get_uint8:(a->int->int)->ctx->a->int->int->unit=fun~get_uint8ctxbufofflen->let(&&)=(land)inlet(lxor)=Int64.(lxor)inlet(land)=Int64.(land)inlet(lor)=Int64.(lor)inlet(lsr)=Int64.(lsr)inlet(lsl)=Int64.(lsl)inletj=refctx.ptinfori=0tolen-1doletv=(ctx.q.(!j/8)land(0xffLlsl((!j&&0x7)*8)))lsr((!j&&0x7)*8)inletv=vlxorInt64.of_int(get_uint8buf(off+i))inctx.q.(!j/8)<-ctx.q.(!j/8)landmasks.(!j&&0x7)lor(vlsl((!j&&0x7)*8));incrj;if!j>=ctx.rsizethen(sha3_keccakfctx.q;j:=0)done;ctx.pt<-!jletunsafe_feed_bytesctxbufofflen=letget_uint8bufoff=Char.code(By.getbufoff)infeed~get_uint8ctxbufofflenletunsafe_feed_bigstring:ctx->Bi.t->int->int->unit=functxbufofflen->letget_uint8bufoff=Char.code(Bi.getbufoff)infeed~get_uint8ctxbufofflenletunsafe_getctx=let(&&)=(land)inlet(lxor)=Int64.(lxor)inlet(lsl)=Int64.(lsl)inletv=ctx.q.(ctx.pt/8)inletv=vlxor(P.paddinglsl((ctx.pt&&0x7)*8))inctx.q.(ctx.pt/8)<-v;letv=ctx.q.((ctx.rsize-1)/8)inletv=vlxor(0x80Llsl(((ctx.rsize-1)&&0x7)*8))inctx.q.((ctx.rsize-1)/8)<-v;sha3_keccakfctx.q;(* Get hash *)(* if the hash size in bytes is not a multiple of 8 (meaning it is
not composed of whole int64 words, like for sha3_224), we
extract the whole last int64 word from the state [ctx.st] and
cut the hash at the right size after conversion to bytes. *)letn=letr=ctx.mdlenmod8inctx.mdlen+ifr=0then0else8-rinlethash=By.createninfori=0to(n/8)-1doBy.unsafe_set_64hash(i*8)(ifSys.big_endianthenBy.swap64ctx.q.(i)elsectx.q.(i))done;By.subhash0ctx.mdlenend