123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347openBls12_381.Ff_sigmoduleMakeFp(S:sigvalprime_order:Z.tend):PRIME_WITH_ROOT_OF_UNITY=structexceptionNot_in_fieldofBytes.ttypet=Z.tletorder=assert(S.prime_order>=Z.of_string"2");S.prime_orderlettwo_z=Z.succZ.oneletfactor_power_of_two=letrecauxin=letq,r=Z.ediv_remntwo_zinifZ.equalrZ.zerothenaux(i+1)qelse(i,n)inaux0(Z.predorder)letlog256n=logn/.log256.letsize_in_bytes=int_of_float(log256(Z.to_floatorder))+1letzero=Z.zeroletone=Z.one(** By default, any bytes sequence is valid because we care about the result
modulo the order *)letcheck_bytes_bs=trueletcopyx=xletis_zeros=Z.equal(Z.eremsorder)Z.zeroletis_ones=Z.equal(Z.eremsorder)Z.oneletrandom?state()=(matchstatewithNone->()|Somes->Random.set_states);letr=Bytes.initsize_in_bytes(fun_->char_of_int(Random.int256))inZ.erem(Z.of_bits(Bytes.to_stringr))orderletnon_null_random?state()=(matchstatewithNone->()|Somes->Random.set_states);letrecaux()=letr=random()inifis_zerorthenaux()elserinaux()letaddab=Z.erem(Z.addab)orderletsubab=Z.erem(Z.subab)orderletmulab=Z.erem(Z.mulab)orderleteqab=Z.equal(Z.eremaorder)(Z.eremborder)letnegatea=suborderaletinverse_exna=ifa=zerothenraiseDivision_by_zeroelseZ.invertaorderletinverse_opta=trySome(Z.invertaorder)withDivision_by_zero->Noneletdiv_exnab=ifb=zerothenraiseDivision_by_zeroelsemula(inverse_exnb)letdiv_optab=ifb=zerothenNoneelseSome(mula(inverse_exnb))letsquarex=mulxxletdoublex=addxxletpowxn=ifZ.equalnZ.zerothenoneelseifis_zeroxthenzeroelseifZ.equalnZ.onethenxelseZ.powmxnorder(* Decimal representation by default *)letof_strings=Z.erem(Z.of_strings)order(* Decimal representation by default *)letto_strings=Z.to_strings(** From a predefined bytes representation, construct a value t. It is not
required that to_bytes (of_bytes_exn t)) = t. By default, little endian
encoding is used and the given element is modulo the prime order *)letof_bytes_exns=Z.erem(Z.of_bits(Bytes.to_strings))order(** From a predefined bytes representation, construct a value t. It is not
required that to_bytes (Option.get (of_bytes_opt t)) = t. By default,
little endian encoding is used and the given element is modulo the prime
order *)letof_bytes_opts=Some(of_bytes_exns)(* Little endian representation *)letto_bytess=letb=Bytes.of_string(Z.to_bitss)inletres=Bytes.makesize_in_bytes'\000'inBytes.blitb0res0(min(Bytes.lengthb)size_in_bytes);resletis_nth_root_of_unitynx=(not(eqxzero))&&is_one(powxn)letget_nth_root_of_unityn=letpred_order=Z.predorderinifZ.gtnpred_order||not(Z.(erempred_ordern)=zero)thenfailwith"n must divide the order of the multiplication subgroup"elseletrecaux()=letr=random()inifis_nth_root_of_unitynrthenrelseaux()inaux()letto_zt=tletof_zt=Z.eremtorderletlegendre_symbolx=ifis_zeroxthenZ.zeroelseifis_one(powx(Z.divexact(Z.predorder)(Z.of_int2)))thenZ.oneelseZ.negZ.oneletis_quadratic_residuex=ifis_zeroxthentrueelseis_one(legendre_symbolx)letrecpick_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 *)lets,q=factor_power_of_twoin(* implies p = 3 mod 4 *)ifs=1then(* r = x^((p + 1) / 4) *)letr=powx(Z.divexact(Z.succorder)(Z.of_string"4"))inSomerelseletreccompute_lowest_n_2th_root_of_unityixupper=letx=squarexinifis_onexthenielseifi=upperthenfailwith"Upperbound should be higher"(* should never happen in this case, just being explicit *)elsecompute_lowest_n_2th_root_of_unity(i+1)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_z(m-i-1))inletm=iinletc=mulbbinlett=multcinletr=mulrbinauxmctrinSome(auxsc(powxq)(powx(Z.divexact(Z.succq)two_z)))letof_intx=of_z(Z.of_intx)let(+)=addlet(*)=mullet(-)=negatelet(**)=powlet(=)=eqlet(/)=div_exnendmoduleMakeFp2(Fp:BASE)(Intf:sig(* Non square residue. Arithmetic is over Fp[X] / X^2 - r *)valnsr:Fp.tend):sigincludeBASEvalcomponents:t->Fp.t*Fp.tend=structexceptionNot_in_fieldofBytes.ttypet=Fp.t*Fp.tletcomponents(a,b)=(a,b)letorder=Z.mulFp.orderFp.orderletsize_in_bytes=Fp.size_in_bytes*2letcheck_bytesb=ifBytes.lengthb=size_in_bytesthenletx=Bytes.subb0(size_in_bytes/2)inlety=Bytes.subb(size_in_bytes/2)(size_in_bytes/2)inFp.check_bytesx&&Fp.check_bytesyelsefalseletcopyx=xletzero=(Fp.zero,Fp.zero)letone=(Fp.one,Fp.zero)letis_zero(x,y)=Fp.(x=zero&&y=zero)letis_one(x,y)=Fp.(x=Fp.one&&y=Fp.zero)letrandom?state()=(matchstatewithNone->()|Somes->Random.set_states);(Fp.random(),Fp.random())letnon_null_random?state()=(matchstatewithNone->()|Somes->Random.set_states);letx=Random.bool()inifxthen(Fp.non_null_random(),Fp.random())else(Fp.random(),Fp.non_null_random())letadd(x1,y1)(x2,y2)=(Fp.(x1+x2),Fp.(y1+y2))letmul(x1,y1)(x2,y2)=letopenFpinlettmp_x=x1*x2inlettmp_y=y1*y2inletx'=tmp_x+(Intf.nsr*tmp_y)inlety'=(x1*y2)+(y1*x2)in(x',y')leteq(x1,y1)(x2,y2)=Fp.(x1=x2&&y1=y2)letnegate(x,y)=(Fp.negatex,Fp.negatey)letsubab=adda(negateb)letaux_inverse(x,y)=(* Let's use square in case of `*` is not optimised for the square case *)letx_square=Fp.squarexinlety_square=Fp.squareyin(* inverse of [x_square - nsr * y_square] *)lettmp_inverse=Fp.(inverse_exn(x_square+Fp.negate(Intf.nsr*y_square)))inletx'=Fp.(x*tmp_inverse)inlety'=Fp.(negatey*tmp_inverse)in(x',y')letinverse_exnx=ifis_zeroxthenraiseDivision_by_zeroelseaux_inversexletinverse_optx=ifis_zeroxthenNoneelseSome(aux_inversex)letdiv_exnab=ifb=zerothenraiseDivision_by_zeroelsemula(inverse_exnb)letdiv_optab=ifb=zerothenNoneelseSome(mula(inverse_exnb))letsquare(a,b)=letab=Fp.(a*b)inFp.(((a+b)*(a+(Intf.nsr*b)))+Fp.negateab+Fp.negate(Intf.nsr*ab),ab+ab)letdoublex=addxxlettwo_z=Z.succZ.oneletrecpowxn=ifZ.equalnZ.zerothenoneelseifis_zeroxthenzeroelseifZ.equalnZ.onethenxelseletn=Z.eremn(Z.predorder)inleta,r=Z.ediv_remntwo_zinletacc=powxainletacc_square=mulaccaccinifZ.equalrZ.zerothenacc_squareelsemulacc_squarex(** From a predefined bytes representation, construct a value t. It is not
required that to_bytes (of_bytes_exn t)) = t. By default, little endian
encoding is used and the given element is modulo the prime order *)letof_bytes_exnb=ifInt.equal(Bytes.lengthb)size_in_bytesthenletx_bytes=Bytes.subb0(Int.divsize_in_bytes2)inlety_bytes=Bytes.subb(Int.divsize_in_bytes2)(Int.divsize_in_bytes2)in(Fp.of_bytes_exnx_bytes,Fp.of_bytes_exny_bytes)elseraise(Not_in_fieldb)(** From a predefined bytes representation, construct a value t. It is not
required that to_bytes (Option.get (of_bytes_opt t)) = t. By default,
little endian encoding is used and the given element is modulo the prime
order *)letof_bytes_optb=ifInt.equal(Bytes.lengthb)size_in_bytesthenletx_bytes=Bytes.subb0(Int.divsize_in_bytes2)inlety_bytes=Bytes.subb(Int.divsize_in_bytes2)(Int.divsize_in_bytes2)inletx=Fp.of_bytes_optx_bytesinlety=Fp.of_bytes_opty_bytesinmatch(x,y)with|None,_|_,None->None|Somex,Somey->Some(x,y)elseNone(* Little endian representation *)letto_bytes(x,y)=letb=Bytes.makesize_in_bytes'\000'inBytes.blit(Fp.to_bytesx)0b0(Int.divsize_in_bytes2);Bytes.blit(Fp.to_bytesy)0b(Int.divsize_in_bytes2)(Int.divsize_in_bytes2);blet(+)=addlet(*)=mullet(-)=negatelet(**)=powlet(=)=eqlet(/)=div_exnend