123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370(*****************************************************************************)(* *)(* Copyright (c) 2020-2021 Danny Willems <be.danny.willems@gmail.com> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)moduleStubs=structtypefrtypescalarexternalallocate_scalar:unit->scalar="allocate_scalar_stubs"externalallocate_fr:unit->fr="allocate_fr_stubs"externalscalar_of_fr:scalar->fr->unit="caml_blst_scalar_from_fr_stubs"externalfr_of_scalar:fr->scalar->unit="caml_blst_fr_from_scalar_stubs"externalscalar_of_bytes_le:scalar->Bytes.t->unit="caml_blst_scalar_of_bytes_stubs"externalscalar_to_bytes_le:Bytes.t->scalar->unit="caml_blst_scalar_to_bytes_stubs"externalcheck_scalar:scalar->bool="caml_blst_check_scalar_stubs"externaladd:fr->fr->fr->unit="caml_blst_fr_add_stubs"externaleq:fr->fr->bool="caml_blst_fr_is_equal_stubs"externalis_zero:fr->bool="caml_blst_fr_is_zero_stubs"externalis_one:fr->bool="caml_blst_fr_is_one_stubs"externalsub:fr->fr->fr->unit="caml_blst_fr_sub_stubs"externalmul:fr->fr->fr->unit="caml_blst_fr_mul_stubs"externalsqr:fr->fr->unit="caml_blst_fr_sqr_stubs"externaleucl_inverse:fr->fr->unit="caml_blst_fr_eucl_inverse_stubs"externalmemcpy:fr->fr->unit="caml_blst_fr_memcpy_stubs"externalfft_inplace:frarray->frarray->int->unit="caml_fft_fr_inplace_stubs"externalmul_map_inplace:frarray->fr->int->unit="caml_mul_map_fr_inplace_stubs"end(* module = Blst_bindings.r (Blst_stubs) *)moduleFr=structexceptionNot_in_fieldofBytes.ttypet=Stubs.frletglobal_buffer=Stubs.allocate_fr()letcopysrc=letdst=Stubs.allocate_fr()inStubs.memcpydstsrc;dstletsize_in_bytes=32letorder=Z.of_string"52435875175126190479447740508185965837690552500527637822603658699938581184513"letpad_if_requirebs=(* Pad to 32 bytes. In anycase, copy the bytes to a new buffer *)ifBytes.lengthbs<size_in_bytesthen(letpadded_bytes=Bytes.makesize_in_bytes'\000'inBytes.blitbs0padded_bytes0(Bytes.lengthbs);padded_bytes)elseBytes.copybsletof_bytes_optbs=ifBytes.lengthbs>size_in_bytesthenNoneelseletbs=pad_if_requirebsinletbuffer_scalar=Stubs.allocate_scalar()inlet()=Stubs.scalar_of_bytes_lebuffer_scalarbsinifStubs.check_scalarbuffer_scalarthen(letbuffer_fr=Stubs.allocate_fr()inStubs.fr_of_scalarbuffer_frbuffer_scalar;Somebuffer_fr)elseNoneletof_bytes_exnbs=letbuffer_opt=of_bytes_optbsinmatchbuffer_optwith|None->raise(Not_in_fieldbs)|Somebuffer->bufferletcheck_bytesbs=ifBytes.lengthbs=size_in_bytesthen(letbuffer_scalar=Stubs.allocate_scalar()inStubs.scalar_of_bytes_lebuffer_scalarbs;Stubs.check_scalarbuffer_scalar)elsefalseletzero=of_bytes_exn(Bytes.makesize_in_bytes'\000')letone=letbytes=Bytes.makesize_in_bytes'\000'inBytes.setbytes0'\001';of_bytes_exnbytesletto_bytesx=letbuffer_bytes=Bytes.makesize_in_bytes'\000'inletbuffer_scalar=Stubs.allocate_scalar()inStubs.scalar_of_frbuffer_scalarx;Stubs.scalar_to_bytes_lebuffer_bytesbuffer_scalar;buffer_bytesleteqxy=Stubs.eqxylet(=)=eqletis_zeros=Stubs.is_zerosletis_ones=Stubs.is_onesletrecrandom?state()=(matchstatewithNone->()|Somestate->Random.set_statestate);letrandom_bytes=Bytes.initsize_in_bytes(fun_->char_of_int@@Random.int256)inletres=of_bytes_optrandom_bytesinmatchreswithNone->random?state:None()|Someres->resletrecnon_null_random?state()=letr=random?state()inifis_zerorthennon_null_random?state()elserletaddxy=letbuffer=Stubs.allocate_fr()inStubs.addbufferxy;bufferletadd_inplacexy=Stubs.addglobal_bufferxy;Stubs.memcpyxglobal_bufferletadd_bulkxs=letbuffer=Stubs.allocate_fr()inList.iter(funx->Stubs.addbufferbufferx)xs;bufferlet(+)=addletmulxy=letbuffer=Stubs.allocate_fr()inStubs.mulbufferxy;bufferletmul_inplacexy=Stubs.mulglobal_bufferxy;Stubs.memcpyxglobal_bufferletmul_bulkxs=letbuffer=Stubs.allocate_fr()inStubs.addbufferbufferone;List.iter(funx->Stubs.mulbufferbufferx)xs;bufferlet(*)=mulletinverse_optx=ifis_zeroxthenNoneelseletbuffer=Stubs.allocate_fr()inStubs.eucl_inversebufferx;Somebufferletinverse_exnx=matchinverse_optxwithNone->raiseDivision_by_zero|Somex->xletinverse_exn_inplacex=ifis_zeroxthenraiseDivision_by_zeroelseStubs.eucl_inverseglobal_bufferx;Stubs.memcpyxglobal_bufferletsubab=letbuffer=Stubs.allocate_fr()inStubs.subbufferab;bufferletsub_inplacexy=Stubs.subglobal_bufferxy;Stubs.memcpyxglobal_bufferletsquarex=letbuffer=Stubs.allocate_fr()inStubs.sqrbufferx;bufferletsquare_inplacex=Stubs.mulglobal_bufferxx;Stubs.memcpyxglobal_bufferletdoublex=x+xletdouble_inplacex=Stubs.addglobal_bufferxx;Stubs.memcpyxglobal_bufferletnegatex=subzeroxletnegate_inplacex=Stubs.subglobal_bufferzerox;Stubs.memcpyxglobal_bufferlet(-)=negateletdiv_exnxy=x*inverse_exnyletdiv_optxy=matchinverse_optywithNone->None|Someinv_y->Some(x*inv_y)let(/)=div_exnlettwo_z=Z.(one+one)letrecpowxn=ifZ.equalnZ.zerothenoneelseifis_zeroxthenzeroelseifZ.equalnZ.onethenxelseletn=Z.eremn(Z.predorder)inlet(a,r)=Z.ediv_remntwo_zinletacc=powxainletacc_square=mulaccaccinifZ.equalrZ.zerothenacc_squareelsemulacc_squarexlet(**)=powletto_strings=letbytes=to_bytessinletz=Z.of_bits(Bytes.to_stringbytes)inZ.to_stringzletof_zz=letz=Bytes.of_string(Z.to_bits(Z.eremzorder))inletx=Bytes.makesize_in_bytes'\000'inBytes.blitz0x0(min(Bytes.lengthz)size_in_bytes);of_bytes_exnxletto_zb=letbytes=to_bytesbinZ.of_bits(Bytes.to_stringbytes)letof_strings=of_z(Z.of_strings)letfactor_power_of_two=letrecauxin=let(q,r)=Z.ediv_remntwo_zinifZ.equalrZ.zerothenauxInt.(succi)qelse(i,n)inaux0(Z.predorder)letlegendre_symbolx=ifis_zeroxthenZ.zeroelseifis_one(powx(Z.divexact(Z.predorder)(Z.of_int2)))thenZ.oneelseZ.negZ.oneletis_quadratic_residuex=ifis_zeroxthentrueelseZ.equal(legendre_symbolx)Z.oneletrecpick_non_square()=letz=random()inifZ.equal(legendre_symbolz)(Z.of_int(-1))thenzelsepick_non_square()letsqrt_optx=ifnot(is_quadratic_residuex)thenNoneelse(* https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm *)let(s,q)=factor_power_of_twoin(* implies p = 3 mod 4 *)ifInt.equals1then(* r = x^((p + 1) / 4) *)letr=powx(Z.divexact(Z.succorder)(Z.of_string"4"))inSomerelseletreccompute_lowest_n_2th_root_of_unity(i:int)xupper:int=letx=squarexinifis_onexthenielseifInt.(equaliupper)thenfailwith"Upperbound should be higher"(* should never happen in this case, just being explicit *)elsecompute_lowest_n_2th_root_of_unity(Int.succi)xupperinletz=pick_non_square()inletc=powzqinletrecauxmctr=ifeqtzerothenzero(* case x is zero *)elseifeqtonethenr(* base case *)elseleti=compute_lowest_n_2th_root_of_unity1tminletb=powc(Z.powtwo_zInt.(pred(submi)))inletm=iinletc=mulbbinlett=multcinletr=mulrbinauxmctrinSome(auxsc(powxq)(powx(Z.divexact(Z.succq)two_z)))moduleM=structtypegroup=ttypescalar=tletzero=zeroletinverse_exn_scalar=inverse_exnletscalar_of_z=of_zletfft_inplace=Stubs.fft_inplaceletmul_map_inplace=Stubs.mul_map_inplaceletcopy=copyendletfft~domain~points=Fft.fft(moduleM)~domain~pointsletfft_inplace~domain~points=letlogn=Z.log2(Z.of_int(Array.lengthpoints))inStubs.fft_inplacepointsdomainlognletifft~domain~points=Fft.ifft(moduleM)~domain~pointsletifft_inplace~domain~points=letn=Array.lengthpointsinletlogn=Z.log2(Z.of_intn)inletn_inv=inverse_exn(of_z(Z.of_intn))inStubs.fft_inplacepointsdomainlogn;Stubs.mul_map_inplacepointsn_invnletcomparexy=Stdlib.compare(to_bytesx)(to_bytesy)endincludeFr