123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208moduleBy=Digestif_bymoduleBi=Digestif_biletnist_padding=0x06Lletkeccak_padding=0x01LmoduleInt64=structincludeInt64external(lsl):int64->int->int64="%int64_lsl"external(lsr):int64->int->int64="%int64_lsr"external(asr):int64->int->int64="%int64_asr"external(lor):int64->int64->int64="%int64_or"external(land):int64->int64->int64="%int64_and"external(lxor):int64->int64->int64="%int64_xor"external(+):int64->int64->int64="%int64_add"let[@inline]lnota=alxor-1Llet[@inline]ror64an=(alsrn)lor(alsl(64-n))let[@inline]rol64an=(alsln)lor(alsr(64-n))endmoduleUnsafe(P:sigvalpadding:int64end)=structtypectx={q:bytes;rsize:int;(* block size *)mdlen:int;(* output size *)mutablept:int;}letdupctx={q=By.copyctx.q;rsize=ctx.rsize;mdlen=ctx.mdlen;pt=ctx.pt}letinitmdlen=letrsize=200-(2*mdlen)in{q=By.make(25*8)'\x00';rsize;mdlen;pt=0}letof_arraya=letb=By.create(8*Array.lengtha)inArray.iteri(funix->By.unsafe_set_64b(i*8)x)a;bletkeccakf_rounds=24letkeccaft_rndc:bytes=of_array[|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:bytes)=letbc=By.create(5*8)inforr=0tokeccakf_rounds-1dolet(lxor)=Int64.(lxor)inletlnot=Int64.lnotinlet(land)=Int64.(land)in(* Theta *)fori=0to4doBy.unsafe_set_64bc(i*8)(By.unsafe_get_64q(i*8)lxorBy.unsafe_get_64q((i+5)*8)lxorBy.unsafe_get_64q((i+10)*8)lxorBy.unsafe_get_64q((i+15)*8)lxorBy.unsafe_get_64q((i+20)*8))done;fori=0to4dolett=By.unsafe_get_64bc((i+4)mod5*8)lxorInt64.rol64(By.unsafe_get_64bc((i+1)mod5*8))1infork=0to4doletj=k*5inBy.unsafe_set_64q((j+i)*8)(By.unsafe_get_64q((j+i)*8)lxort)donedone;(* Rho Pi *)lett=ref(By.unsafe_get_64q8)infori=0to23doletj=keccakf_piln.(i)inletv=By.unsafe_get_64q(j*8)inBy.unsafe_set_64q(j*8)(Int64.rol64!tkeccaft_rotc.(i));t:=vdone;(* Chi *)fork=0to4doletj=k*5infori=0to4doBy.unsafe_set_64bc(i*8)(By.unsafe_get_64q((j+i)*8))done;fori=0to4doBy.unsafe_set_64q((j+i)*8)(By.unsafe_get_64q((j+i)*8)lxor(lnot(By.unsafe_get_64bc((i+1)mod5*8))landBy.unsafe_get_64bc((i+2)mod5*8)))donedone;(* Iota *)By.unsafe_set_64q0(By.unsafe_get_64q0lxorBy.unsafe_get_64keccaft_rndc(r*8))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-1doletq=By.unsafe_get_64ctx.q(!j/8*8)inletv=(qland(0xffLlsl((!j&&0x7)*8)))lsr((!j&&0x7)*8)inletv=vlxorInt64.of_int(get_uint8buf(off+i))inBy.unsafe_set_64ctx.q(!j/8*8)(qlandmasks.(!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=By.unsafe_get_64ctx.q(ctx.pt/8*8)inletv=vlxor(P.paddinglsl((ctx.pt&&0x7)*8))inBy.unsafe_set_64ctx.q(ctx.pt/8*8)v;letv=By.unsafe_get_64ctx.q((ctx.rsize-1)/8*8)inletv=vlxor(0x80Llsl(((ctx.rsize-1)&&0x7)*8))inBy.unsafe_set_64ctx.q((ctx.rsize-1)/8*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)-1doletv=By.unsafe_get_64ctx.q(i*8)inBy.unsafe_set_64hash(i*8)(ifSys.big_endianthenBy.swap64velsev)done;By.subhash0ctx.mdlenend