123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346(*****************************************************************************)(* *)(* 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"externalcallocate_fr:unit->fr="callocate_fr_stubs"externalmallocate_fr:unit->fr="mallocate_fr_stubs"externalscalar_of_fr:scalar->fr->int="caml_blst_scalar_from_fr_stubs"externalfr_of_scalar:fr->scalar->int="caml_blst_fr_from_scalar_stubs"externalfr_of_bytes_le:fr->Bytes.t->bool="caml_blst_fr_from_lendian_stubs"externalfr_to_bytes_le:Bytes.t->fr->int="caml_blst_lendian_from_fr_stubs"externalscalar_of_bytes_le:scalar->Bytes.t->int="caml_blst_scalar_of_bytes_stubs"externalscalar_to_bytes_le:Bytes.t->scalar->int="caml_blst_scalar_to_bytes_stubs"externalcheck_scalar:scalar->bool="caml_blst_check_scalar_stubs"externaladd:fr->fr->fr->int="caml_blst_fr_add_stubs"externaleq:fr->fr->bool="caml_blst_fr_is_equal_stubs"externalcneg:fr->fr->bool->bool="caml_blst_fr_cneg_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->int="caml_blst_fr_sub_stubs"externalmul:fr->fr->fr->int="caml_blst_fr_mul_stubs"externalpow:fr->fr->Bytes.t->int->int="caml_blst_fr_pow_stubs"externalsqr:fr->fr->int="caml_blst_fr_sqr_stubs"externaleucl_inverse:fr->fr->int="caml_blst_fr_eucl_inverse_stubs"externalmemcpy:fr->fr->int="caml_blst_fr_memcpy_stubs"externalinner_product:fr->frarray->frarray->int->int="caml_blst_fr_inner_product_stubs"end(* module = Blst_bindings.r (Blst_stubs) *)moduleFr=structexceptionNot_in_fieldofBytes.ttypet=Stubs.frletcopysrc=letdst=Stubs.mallocate_fr()inignore@@Stubs.memcpydstsrc;dstletmemcpyab=ignore@@Stubs.memcpyabletsize_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=Stubs.mallocate_fr()inletis_ok=Stubs.fr_of_bytes_lebufferbsinifis_okthenSomebufferelseNoneletof_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()inignore@@Stubs.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'inignore@@Stubs.fr_to_bytes_lebuffer_bytesx;buffer_bytesletsize_in_memory=Obj.reachable_words(Obj.reprone)*8leteqxy=Stubs.eqxylet(=)=eqletis_zeros=Stubs.is_zerosletis_ones=Stubs.is_onesletrecrandom?state()=letrandom_int=matchstatewith|None->Random.int|Somestate->Random.State.intstateinletrandom_bytes=Bytes.initsize_in_bytes(fun_->char_of_int@@random_int256)inletres=of_bytes_optrandom_bytesinmatchreswithNone->random?state()|Someres->resletrecnon_null_random?state()=letr=random?state()inifis_zerorthennon_null_random?state()elserletaddxy=letbuffer=Stubs.mallocate_fr()inignore@@Stubs.addbufferxy;bufferletadd_inplaceresab=ignore@@Stubs.addresabletadd_bulkxs=letbuffer=Stubs.callocate_fr()inList.iter(funx->ignore@@Stubs.addbufferbufferx)xs;bufferlet(+)=addletmulxy=letbuffer=Stubs.mallocate_fr()inignore@@Stubs.mulbufferxy;bufferletmul_inplaceresab=ignore@@Stubs.mulresabletmul_bulkxs=letbuffer=Stubs.callocate_fr()inignore@@Stubs.addbufferbufferone;List.iter(funx->ignore@@Stubs.mulbufferbufferx)xs;bufferlet(*)=mulletinverse_optx=ifis_zeroxthenNoneelseletbuffer=Stubs.mallocate_fr()inignore@@Stubs.eucl_inversebufferx;Somebufferletinverse_exnx=matchinverse_optxwithNone->raiseDivision_by_zero|Somex->xletinverse_exn_inplaceresx=ifis_zeroxthenraiseDivision_by_zeroelseignore@@Stubs.eucl_inverseresxletsubab=letbuffer=Stubs.mallocate_fr()inignore@@Stubs.subbufferab;bufferletsub_inplaceresxy=ignore@@Stubs.subresxyletsquarex=letbuffer=Stubs.mallocate_fr()inignore@@Stubs.sqrbufferx;bufferletsquare_inplaceresx=ignore@@Stubs.sqrresxletdoublex=x+xletdouble_inplaceresx=ignore@@Stubs.addresxxletnegatex=letbuffer=Stubs.mallocate_fr()inignore@@Stubs.cnegbufferxtrue;bufferletnegate_inplaceresx=ignore@@Stubs.cnegresxtruelet(-)=negateletdiv_exnxy=x*inverse_exnyletdiv_optxy=matchinverse_optywithNone->None|Someinv_y->Some(x*inv_y)let(/)=div_exnlettwo_z=Z.(one+one)letpowxn=letn=Z.eremn(Z.predorder)inletbuffer=Stubs.mallocate_fr()inletexp=Z.to_bitsn|>Bytes.unsafe_of_stringinletexp_len=Z.numbitsninignore@@Stubs.powbufferxexpexp_len;bufferlet(**)=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=letq,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?state:None()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 *)lets,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)))letcomparexy=Stdlib.compare(to_bytesx)(to_bytesy)letinner_product_optab=ifArray.lengtha<>Array.lengthbthenNoneelseletres=copyzeroinignore@@Stubs.inner_productresab(Array.lengtha);Someresletinner_product_exnab=matchinner_product_optabwith|None->raise(Invalid_argument"Both parameters must be of the same length")|Somex->xletof_intx=of_z(Z.of_intx)endincludeFr