123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158(*****************************************************************************)(* *)(* 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_stdlibletone=S.oneletmone=S.negateonemoduleMakeAffine(Curve:Mec.CurveSig.AffineEdwardsT):Affine_curve_intf.EDWARDS=functor(L:LIB)->structmoduleL=LopenLtypepoint=scalar*scalarletscalar_order=Curve.Scalar.orderletbase_order=Curve.Base.orderletparam_d=Curve.(d|>Base.to_z)|>S.of_zletinput_point?(kind=`Private)(u,v)=Input.(pair(scalaru)(scalarv))|>input~kindletget_x_coordinatep=of_pairp|>fstletget_y_coordinatep=of_pairp|>sndletid=(S.zero,S.one)(* 1 constraint *)letis_on_curvep=with_label~label:"Edwards.is_on_curve"@@letx,y=of_pairpinlet*x2=Num.squarexinlet*y2=Num.squareyin(* x_l = x^2 *)(* x_r = y^2 *)(* -1 * x^2 + 1 * y^2 - d * x^2 y^2 - 1 = 0 *)(* | | | | | *)(* ql qr qm qc qo *)letqm=S.negateparam_dinlet*o=Num.custom~qc:mone~ql:mone~qr:one~qmx2y2inNum.is_zeroo(* 1 constraint *)letassert_is_on_curvep=with_label~label:"Edwards.is_on_curve"@@letx,y=of_pairpinlet*x2=Num.squarexinlet*y2=Num.squareyinletqm=S.negateparam_din(* The last wire is multiplied by 0 so we can put any value, we chose x here. *)Num.assert_custom~qc:mone~ql:mone~qr:one~qmx2y2xletfrom_coordinatesxy=with_label~label:"Edwards.from_coordinates"@@letp=pairxyinwith_bool_check(is_on_curvep)>*retpletunsafe_from_coordinatesxy=with_label~label:"Edwards.unsafe_from_coordinates"(pairxy|>ret)(* P1:(u1, v1) + P2:(u2, v2) = P3:(u3, v3)
2 constraints
*)letaddp1p2=Ecc.edwards_addp1p2letcond_addp1p2b=Ecc.edwards_cond_addp1p2b(* 2 * P1:(u1, v1) = P1:(u1, v1) + P1:(u1, v1) = P3:(u3, v3) as the addition is complete
12 constraints
*)letdoublep=addppletpoint_or_zeropointb=with_label~label:"Edwards.point_or_zero"@@letp_x=get_x_coordinatepointinletp_y=get_y_coordinatepointin(* if b = 1, return (p_u, p_v); otherwise the zero point (0, 1) *)letb=scalar_of_boolbinlet*u=Num.mulbp_xinlet*v=Num.custom~qr:mone~qc:one~qm:onep_ybinret@@pairuvletscalar_mulsp=let*one=Bool.constanttrueinwith_label~label:"Edwards.scalar_mul"@@letrev_s=List.rev(of_lists)inlet*init=point_or_zerop(List.hdrev_s)infoldM(funaccb->let*acc=cond_addaccacconeincond_addaccpb)init(List.tlrev_s)(* Computes \prod_i p_i^s_i with inputs:
- ls: [[s_11; ...; s_1m]; ...; [s_n1; ...; s_nm]]
- lp: [p1; ...; pn] *)letmulti_scalar_mullslp=let*one=Bool.constanttrueinwith_label~label:"Edwards.multi_scalar_mul"@@(* Check we apply Shamir's trick on at least 2 points *)let()=assert(List.(length(of_listls)>1))in(* Converting ls to ls' = [[s_11; ...; s_n1]; ...; [s_1m; ...; s_nm]] *)letls=List.mapof_list(of_listls)|>Utils.transpose|>List.revinletpoints=of_listlpin(* Check we perform scalar multiplications on lists of at least 1 bit *)assert(List.(lengthls>0));(* Initializing the accumulator with the first round of Shamir's trick *)letheads=List.hdlsinlet*init=point_or_zero(List.hdpoints)(List.hdheads)inlet*init=fold2Mcond_addinit(List.tlpoints)(List.tlheads)in(* Applying Shamir's trick on the rest of the rounds *)foldM(funacclb->let*acc=cond_addaccacconeinfold2Mcond_addaccpoints(of_listlb))initList.(mapto_list(tlls))end