123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115moduletypePARAMETERS=sigvalwidth:intvalfull_rounds:intvalpartial_rounds:intvalround_constants:stringarrayvallinear_transformation:stringarrayarrayvalpartial_round_idx_to_permute:intvalalpha:Z.tendmoduleMake(Param:PARAMETERS)(Scalar:Bls12_381.Ff_sig.PRIME)=structopenParam(* Verify: - the constants are consistent - the sbox is a permutation, i.e.
pgcd(alpha, p - 1) = 1
IMPROVEME: - Verify the linear layer is secure. It requiers to implement
different algorithms in Caml, and it does require a bit of code about
linear algebra not available in the ecosystem AFAIK. Use the sage scripts
in the meantime *)let()=assert(Array.lengthlinear_transformation=width);assert(Array.for_all(funline->Array.lengthline=width)linear_transformation);assert(Z.(equal(gcd(Z.predScalar.order)alpha)one))letlinear_transformation=Array.map(Array.mapScalar.of_string)linear_transformationletround_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;vletsubstitutionx=Scalar.(powxalpha)(* 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_substitution_last_elems=lets=s.stateins.(partial_round_idx_to_permute)<-substitutions.(partial_round_idx_to_permute)letapply_substitutions=lets=s.stateinfori=0toArray.lengths-1dos.(i)<-substitutions.(i)doneletapply_permutationmv=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_partial_rounds=apply_round_keys;apply_substitution_last_elems;apply_permutationlinear_transformationsletapply_full_rounds=apply_round_keys;apply_substitutions;apply_permutationlinear_transformationsletapplys=s.i_round_key<-0;for_i=0to(full_rounds/2)-1doapply_full_roundsdone;for_i=0topartial_rounds-1doapply_partial_roundsdone;for_i=0to(full_rounds/2)-1doapply_full_roundsdoneletgets=Array.copys.stateend