123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155(*****************************************************************************)(* *)(* MIT License *)(* Copyright (c) 2022 Nomadic Labs <contact@nomadic-labs.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. *)(* *)(*****************************************************************************)openLang_coreopenLang_stdlibletzero=S.zeroletone=S.onelettwo=S.addoneoneletthree=S.addtwooneletmone=S.negateoneletmtwo=S.negatetwomoduletypeAFFINE=Affine_curve_intf.WEIERSTRASSmoduleMakeAffine(Curve:Mec.CurveSig.AffineWeierstrassT):AFFINE=functor(L:LIB)->structmoduleL=LopenLtypepoint=scalar*scalarletscalar_order=Curve.Scalar.orderletbase_order=Curve.Base.orderletparam_a=Curve.a|>Curve.Base.to_z|>S.of_zletinput_point?(kind=`Private)(x,y)=Input.(pair(scalarx)(scalary))|>input~kindletget_x_coordinatep=of_pairp|>fstletget_y_coordinatep=of_pairp|>sndletis_on_curvep=with_label~label:"Weierstrass.is_on_curve"@@letx,y=of_pairpinlet*x2=Num.squarexinlet*y2=Num.squareyinletql=param_ainletqc=Curve.b|>Curve.Base.to_z|>S.of_zinlet*tmp=Num.custom~qm:one~ql~qcxx2inlet*o=Num.custom~ql:mone~qr:oney2tmpinNum.is_zeroo(* 2 constraints *)letassert_is_on_curvep=with_label~label:"Weierstrass.assert_is_on_curve"@@letx,y=of_pairpinlet*x2=Num.squarexinlet*y2=Num.squareyin(* - y^2 + x^3 + a * x + b = 0
<=> | 1 * x * x^2 + a * x + b - 1 * tmp = 0
| | | | |
| qm ql qc qo
| -1 * y^2 + 1 * tmp = 0
| |
ql qr
*)letql=param_ainletqc=Curve.b|>Curve.Base.to_z|>S.of_zinlet*tmp=Num.custom~qm:one~ql~qcxx2inNum.assert_custom~ql:mone~qr:oney2tmptmpletfrom_coordinatesxy=with_label~label:"Weierstrass.from_coordinates"@@letp=pairxyinassert_is_on_curvep>*retpletunsafe_from_coordinatesxy=with_label~label:"Weierstrass.unsafe_from_coordinates"(pairxy|>ret)(* 2 constraints *)letaddp1p2=Ecc.weierstrass_addp1p2(* 2 * P1:(x1, y1) = P3:(x2, y2) (!= P1:(x1, y1) + P1:(x1, y1) which fails as the addition is not complete)
x2 = [(3 * x1^2 + a) / (2 * y1)]^2 - 2 * x1
y2 = [(3 * x1^2 + a) / (2 * y1)] * (x1 - x2) - y1
9 constraints
*)letdoublep=with_label~label:"Weierstrass.double"@@letx,y=of_pairpin(* lambda = (3 * x^2 + a) / (2 * y) *)let*num_lambda=Num.custom~qm:threexx~qc:param_ainlet*lambda=Num.div~den_coeff:twonum_lambdayin(* x_r = lambda^2 - 2 * x *)let*lambda_square=Num.squarelambdainlet*x_r=Num.addlambda_square~qr:mtwoxin(* y_r = lambda * (x - x_r) - y *)let*x_minus_xr=Num.add~qr:monexx_rinlet*left=Num.mullambdax_minus_xrinlet*y_r=Num.add~qr:moneleftyinpairx_ry_r|>ret(* /!\ This function may not return the expected result when
s > Curve.Base.order, because it uses incomplete formulas & thus doesn't
handle the point at infinity *)letscalar_mulsp=with_label~label:"Weierstrass.scalar_mul"@@let*flag=Bool.constantfalseinletinit=pairpflaginlet*res=foldM(funaccb->letacc_res,acc_flag=of_pairaccinlet*acc_res=doubleacc_resinlet*sum=addacc_respinlet*ite=Bool.ifthenelseacc_flagsumpinlet*acc_res=Bool.ifthenelsebiteacc_resinlet*acc_flag=Bool.boracc_flagbinletacc=pairacc_resacc_flaginretacc)init(List.rev(of_lists))inletresult,_=of_pairresinretresultend