123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207(**
https://github.com/daira/jubjub
Base field: 52435875175126190479447740508185965837690552500527637822603658699938581184513 (254 bits - 32 bytes)
Scalar field: 6554484396890773809930967563523245729705921265872317281365359162392183254199 (251 bits - 32 bytes)
Base field multiplicative subgroup decomposition:
2^32 * 3 * 11 * 19 * 10177 * 125527 * 859267 * 906349^2 * 2508409 * 2529403 * 52437899 * 254760293^2
Prime field multiplication subgroup decomposition:
2 * 3 * 12281 * 88951556562858260862727893541829461901934170206990707615630637602694993
*)moduleBase=Ff.MakeFp(structletprime_order=Z.of_string"52435875175126190479447740508185965837690552500527637822603658699938581184513"end)moduleScalar=Ff.MakeFp(structletprime_order=Z.of_string"6554484396890773809930967563523245729705921265872317281365359162392183254199"end)moduleAffineEdwards:sigincludeEc_sig.AffineEdwardsTwithtypeBase.t=Base.tandtypeScalar.t=Scalar.tvalof_compressed_exn:Bytes.t->tvalof_compressed_opt:Bytes.t->toptionvalto_compressed:t->Bytes.tend=structincludeEc.MakeAffineEdwards(Base)(Scalar)(structleta=Base.(negateone)letd=Base.of_string"19257038036680949359750312669786877991949435402254120286184196891950884077233"letcofactor=Z.of_string"8"letbytes_generator=Bytes.concatBytes.empty[Base.(to_bytes(of_string"8076246640662884909881801758704306714034609987455869804520522091855516602923"));Base.(to_bytes(of_string"13262374693698910701929044844600465831413122818447359594527400194675274060458"));]end)letof_compressed_optb=(* required to avoid side effect! *)letb=Bytes.copybinletlength=Bytes.lengthbiniflength<>32thenNoneelse(* We get the last bit of the input, representing the bit of u. We also
remove the last bit from the bytes we received
*)letlast_byte=int_of_char@@Bytes.getb(length-1)inletsign=last_bytelsr7inletlast_byte_without_sign=last_byteland0b01111111inBytes.setb(length-1)(char_of_intlast_byte_without_sign);(* We compute u *)letv=Base.of_bytes_optbinmatchvwith|None->None|Somev->((* Isolate u^2 *)(* a u^2 + v^2 = 1 + d u^2 v^2 *)(* <==> a u^2 - d u^2 v^2 = 1 - v^2 *)(* <==> u^2 (a - d v^2) = 1 - v^2 *)(* <==> u^2 = (1 - v^2) / (a - d v^2) *)letvv=Base.(v*v)inletdvv=Base.(d*vv)inletnum=Base.(one+negatevv)inletden=Base.(a+negatedvv)inletuu=Base.(num/den)inletu_opt=Base.sqrt_optuuinletu=matchu_optwith|None->None|Someu->(* computed before for constant time *)letnegated_u=Base.negateuinletu_first_byte=Bytes.get(Base.to_bytesu)0inletis_sign_flipped=int_of_charu_first_bytelxorsignland1inSome(ifis_sign_flipped=0thenuelsenegated_u)inmatchuwith|Someu->Some(unsafe_from_coordinates~u~v)|None->None)letof_compressed_exnb=matchof_compressed_optbwith|None->raise(Not_on_curveb)|Somep->pletto_compressedp=letu=get_u_coordinatepinletv=get_v_coordinatepinletu_bytes=Base.to_bytesuinletv_bytes=Base.to_bytesvinletu_first_byte=int_of_char(Bytes.getu_bytes0)inletv_last_byte=int_of_char(Bytes.getv_bytes(Base.size_in_bytes-1))in(* Get the first bit of u, i.e. the sign of u *)letsign_of_u=u_first_byteland0b00000001in(* Set the last bit of the last byte of v to the sign of u *)letv_last_byte_with_u=v_last_bytelor(sign_of_ulsl7)inBytes.setv_bytes(Base.size_in_bytes-1)(char_of_intv_last_byte_with_u);v_bytesendmoduleAffineMontgomery=Ec.MakeAffineMontgomery(Base)(Scalar)(structleta=Base.of_string"40962"letb=Base.of_string"52435875175126190479447740508185965837690552500527637822603658699938581143549"letcofactor=Z.of_int8letbytes_generator=Bytes.concatBytes.empty[Base.(to_bytes(of_string"37380265172535953876205871964221324158436172047572074969815349807835370906304"));Base.(to_bytes(of_string"14806724895810515565537763359156126150942240025109370624530515646853716216120"));]end)moduleAffineWeierstrass=Ec.MakeAffineWeierstrass(Base)(Scalar)(structleta=Base.of_string"52296097456646850916096512823759002727550416093741407922227928430486925478210"letb=Base.of_string"48351165704696163914533707656614864561753505123260775585269522553028192119009"letcofactor=Z.of_int8letbytes_generator=Bytes.concatBytes.empty[Base.(to_bytes(of_string"33835869156188682335217394949746694649676633840125476177319971163079011318731"));Base.(to_bytes(of_string"43777270878440091394432848052353307184915192688165709016756678962558652055320"));]end)letfrom_affine_edwards_to_affine_montgomeryp=Ec.from_affine_edwards_to_affine_montgomery(moduleAffineEdwards)(moduleAffineMontgomery)pletfrom_affine_montgomery_to_affine_edwardsp=Ec.from_affine_montgomery_to_affine_edwards(moduleAffineMontgomery)(moduleAffineEdwards)pletfrom_affine_montgomery_to_affine_weierstrassp=Ec.from_affine_montgomery_to_affine_weierstrass(moduleAffineMontgomery)(moduleAffineWeierstrass)pletfrom_affine_edwards_to_affine_weierstrassp=letp=from_affine_edwards_to_affine_montgomerypinOption.bindp(funopt->Ec.from_affine_montgomery_to_affine_weierstrass(moduleAffineMontgomery)(moduleAffineWeierstrass)opt)