123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264moduletypeElt_sig=sigtypetvalsize:intvalallocate:unit->tvalzero:tvaleq:t->t->boolendmoduletypeCarray_sig=sigtypettypeeltvalt:tRepr.tvalempty:t(** [allocate len] creates a C array of size [len] initialized with zeros. *)valallocate:int->t(** [init n f] returns a fresh C array of length [n], with element number [i]
initialized to the result of [f i]. *)valinit:int->(int->elt)->t(** [degree p] returns the index of the last non-zero element of [p].
Returns -1 if all elements of [p] are zero. *)valdegree:t->int(** [erase p n] fills with zeros the first [n] elements of [p]. *)valerase:t->int->unit(** [length c] returns the length of a C array [c] *)vallength:t->int(** [get c i] returns the [i]-th element of a C array [c] *)valget:t->int->elt(** [get_inplace c i res] copies the [i]-th element of a C array [c] in res *)valget_inplace:t->int->elt->unit(** [iter_copy_elt f a] applies function [f] in turn to a **copy** of all
the elements of [a]. It is equivalent to
[f a.(0); f a.(1); ...; f a.(length a - 1); ()]. *)valiter_copy_elt:(elt->unit)->t->unit(** Same as {!iter_copy_elt}, but the
function is applied to the index of the element as first argument,
and a **copy** of the element itself as second argument. *)valiteri_copy_elt:(int->elt->unit)->t->unitvalset:t->elt->int->unit(** [copy c] copies [len] elements from a C array [c] starting from position [offset] *)valcopy:?offset:int->?len:int->t->t(** [blit src src_off dst dst_off len] copies [len] elements from [src] to
[dst] starting at the respective offsets. *)valblit:t->src_off:int->t->dst_off:int->len:int->unit(** [equal a offset1 b offset2] returns true if the segments of [len] elements of
[a] and [b] are equal starting from their respective offsets [offset1] (for [a])
and [offset2] (for [b]). *)valequal:t->offset1:int->t->offset2:int->len:int->bool(** [to_array c] converts a C array [c] to an OCaml array *)valto_array:?offset:int->?len:int->t->eltarray(** [of_array c] converts an OCaml array [c] to a C array *)valof_array:eltarray->tvalof_bigstring:Bigstringaf.t->tvalto_bigstring:t->Bigstringaf.t(** [eq a b] returns true if C arrays [a] and [b] are equals *)valeq:t->t->bool(** [sub a off len] extracts a sub-array of [a] *)valsub:t->off:int->len:int->t(** [fold_left_map] is a combination of fold_left and map that threads an
accumulator through calls to [f]. *)valfold_left_map:('acc->elt->'acc*elt)->'acc->t->'acc*tend(** Note that an unsafe type casting is performed by this module.
USE WITH CARE!
The type of get and set changes with whatever Elt.t is given as input.
This works because Elt also indicates the size in bytes which would be
read/written and because Elt is assumed to be backed by a custom block
(it is accessed with [Data_custom_val]). *)moduleMake(Elt:Elt_sig):Carray_sigwithtypeelt=Elt.t=structtypet=Bigstringaf.ttypeelt=Elt.tmoduleStubs=struct(** [get elt p i size] copies the [i]-th element of a given array [p] in [elt],
assuming elements of [size] bytes.
- requires: [0 <= i < size p]
- ensures: [elt = p[i]] *)externalget:elt->t->int->int->unit="caml_bls12_381_polynomial_polynomial_carray_get_stubs"[@@noalloc](** [set p elt i size] copies [elt] in the [i]-th element of [p],
assuming elements of [size] bytes.
- requires: [0 <= i < size p]
- ensures: [elt = p[i]] *)externalset:t->elt->int->int->unit="caml_bls12_381_polynomial_polynomial_carray_set_stubs"[@@noalloc](** [memset_zero p n] writes [n] bytes of zeros in [p]
- requires: [n <= size p] *)externalmemset_zero:t->int->unit="caml_bls12_381_polynomial_polynomial_memset_zero_stubs"[@@noalloc]endlett:tRepr.t=Repr.(mapstring(funs->Bigstringaf.of_string~off:0~len:(String.lengths)s)Bigstringaf.to_string)letlengtha=Bigstringaf.lengtha/Elt.sizeletempty=Bigstringaf.emptyletallocaten=ifn<1thenraise@@Invalid_argument"allocate: size should be >= 1";letsize=Elt.size*ninletres=Bigstringaf.createsizeinStubs.memset_zeroressize;resletinitnf=ifn<1thenraise@@Invalid_argument"init: size should be >= 1";letres=Bigstringaf.create(Elt.size*n)infori=0ton-1doStubs.setres(fi)iElt.sizedone;resletsubt~off~len=Bigstringaf.subt~off~len:(len*Elt.size)leterasepn=ifn<0||n>lengthpthenraise@@Invalid_argument"erase: invalid length";Stubs.memset_zerop(Elt.size*n)letgetpi=ifi<0||i>=lengthpthenraise@@Invalid_argument"get: index out of bounds";letres=Elt.allocate()inStubs.getrespiElt.size;resletget_unsafepi=letres=Elt.allocate()inStubs.getrespiElt.size;res(* TODO: implement loop in C
See https://gitlab.com/nomadic-labs/cryptography/privacy-team/-/issues/215 *)letdegreea=letrecauxi=ifi=-1then-1elseifElt.eq(getai)Elt.zerothenaux(i-1)elseiinaux(lengtha-1)letget_inplacepires=ifi<0||i>=lengthpthenraise@@Invalid_argument"get: index out of bounds";Stubs.getrespiElt.sizeletiter_copy_eltfa=fori=0tolengtha-1dof(get_unsafeai)doneletiteri_copy_eltfa=fori=0tolengtha-1dofi(get_unsafeai)doneletsetpfri=ifi<0||i>=lengthpthenraise@@Invalid_argument"set: index out of bounds";Stubs.setpfriElt.sizeletto_array?(offset=0)?lenp=letlen=Option.value~default:(lengthp-offset)leniniflen<0||offset<0||lengthp-offset<lenthenraise@@Invalid_argument(Format.sprintf"to_array: invalid len %d or offset %d for size %d"lenoffset(lengthp));Array.initlen(funi->getp(offset+i))letof_arraycaml_array=letn=Array.lengthcaml_arrayinletres=allocateninArray.iteri(funig->setresgi)caml_array;resletblitsrc~src_offdst~dst_off~len=letsrc_off=src_off*Elt.sizeinletdst_off=dst_off*Elt.sizeinletlen=len*Elt.sizeinBigstringaf.blitsrc~src_offdst~dst_off~lenletcopy?(offset=0)?lenp=letlen=Option.value~default:(lengthp-offset)leniniflen<0||offset<0||lengthp-offset<lenthenraise@@Invalid_argument(Format.sprintf"copy: invalid len %d or offset %d for size %d"lenoffset(lengthp));letres=allocateleninblitp~src_off:offsetres~dst_off:0~len;resletequala~offset1b~offset2~len=Bigstringaf.memcmpaoffset1boffset2(len*Elt.size)=0leteqab=letlen_a=lengthainletlen_b=lengthbiniflen_a<>len_bthenfalseelseequala~offset1:0b~offset2:0~len:len_aletof_bigstringb=bletto_bigstringb=bletfold_left_mapfaccinput_array=letlen=lengthinput_arrayiniflen<1thenraise@@Invalid_argument"allocate: size should be >= 1"elseletacc,elt=facc(get_unsafeinput_array0)inletoutput_array=allocateleninsetoutput_arrayelt0;letacc=refaccinfori=1tolen-1doletacc',elt=f!acc(get_unsafeinput_arrayi)inacc:=acc';setoutput_arrayeltidone;(!acc,output_array)end