12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697moduletypePARAMETERS=sig(** The state size *)valwidth:int(** The number of rounds *)valrounds:int(** The round constants, given in decimal representation *)valround_constants:stringarray(** The MDS matrix, given in decimal representation *)valmds_matrix:stringarrayarrayvalalpha:Z.tvalalphainv:Z.tendmoduleMake(Param:PARAMETERS)(Scalar:Bls12_381.Ff_sig.PRIME)=structopenParam(* Verify the constants are consistent *)let()=assert(Array.lengthmds_matrix=width);assert(Array.for_all(funline->Array.lengthline=width)mds_matrix)letmds_matrix=Array.map(Array.mapScalar.of_string)mds_matrixletround_constants=Array.mapScalar.of_stringround_constants(* Initialize only once an array for the MDS matrix multiplication *)letres=Array.makewidthScalar.zerotypestate={mutablei_round_key:int;state:Scalar.tarray}letinitstate=ifArray.lengthstate!=widththenfailwith(Printf.sprintf"State length is %d, but the width of the strategy is %d"(Array.lengthstate)width)else{i_round_key=0;state=Array.copystate}letget_next_round_keys=letv=round_constants.(s.i_round_key)ins.i_round_key<-s.i_round_key+1;v(* Functions prefixed with apply_ are modifying the state given in
parameters *)letapply_round_keys=letstate=s.stateinfori=0toArray.lengthstate-1dostate.(i)<-Scalar.(get_next_round_keys+state.(i))doneletapply_nonlinear_alphas=lets=s.stateinfori=0toArray.lengths-1dos.(i)<-Scalar.pows.(i)alphadoneletapply_nonlinear_alphainvs=lets=s.stateinfori=0toArray.lengths-1dos.(i)<-Scalar.pows.(i)alphainvdoneletapply_linearmv=letv=v.stateinforj=0towidth-1dofork=0towidth-1dores.(k)<-Scalar.(res.(k)+(m.(k).(j)*v.(j)))donedone;forj=0towidth-1dov.(j)<-res.(j);res.(j)<-Scalar.zerodoneletapply_rounds=apply_nonlinear_alphas;apply_linearmds_matrixs;apply_round_keys;apply_nonlinear_alphainvs;apply_linearmds_matrixs;apply_round_keysletapplys=s.i_round_key<-0;for_i=0torounds-1doapply_roundsdoneletgets=Array.copys.stateend