123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208(*****************************************************************************)(* *)(* 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_stdlibmoduletypeCURVE_PARAMETERS=sigvala:S.tvald:S.tvalscalar_order:Z.tvalbase_order:Z.tendletzero=S.zeroletone=S.onelettwo=S.addoneoneletmone=S.negateonemoduletypeAFFINE=functor(L:LIB)->sigopenLtypepoint=scalar*scalarvalinput_point:?kind:input_kind->S.t*S.t->pointreprtvalis_on_curve:pointrepr->boolreprt(** Also checks that the point is on the curve (but not necessarily in the
subgroup). *)valfrom_coordinates:scalarrepr->scalarrepr->pointreprtvalunsafe_from_coordinates:scalarrepr->scalarrepr->pointreprtvalget_u_coordinate:pointrepr->scalarreprvalget_v_coordinate:pointrepr->scalarrepr(** The identity element of the curve (0, 1). *)valid:S.t*S.tvaladd:pointrepr->pointrepr->pointreprtvalcond_add:pointrepr->pointrepr->boolrepr->pointreprtvaldouble:pointrepr->pointreprtvalscalar_mul:boollistrepr->pointrepr->pointreprtvalscalar_order:Z.tvalbase_order:Z.tvalmulti_scalar_mul:boollistlistrepr->pointlistrepr->pointreprtendmoduleMakeAffine(Params:CURVE_PARAMETERS):AFFINE=functor(L:LIB)->structincludeParamsopenLtypepoint=scalar*scalarletinput_point?(kind=`Private)(u,v)=Input.(pair(scalaru)(scalarv))|>input~kindletget_u_coordinatep=of_pairp|>fstletget_v_coordinatep=of_pairp|>sndletid=(S.zero,S.one)(* 1 constraint *)letis_on_curvep=with_label~label:"Edwards.is_on_curve"@@letu,v=of_pairpinlet*u2=Num.squareuinlet*v2=Num.squarevin(* x_l = u^2 *)(* x_r = v^2 *)(* -1 * u^2 + 1 * v^2 - d * u^2 v^2 - 1 = 0 *)(* | | | | | *)(* ql qr qm qc qo *)letqm=S.(negateParams.d)in(* The last wire is multiplied by 0 so we can put any value, we chose u here. *)let*o=Num.custom~qc:mone~ql:mone~qr:one~qmu2v2inNum.is_zerooletfrom_coordinatesuv=with_label~label:"Edwards.from_coordinates"@@letp=pairuvinwith_bool_check(is_on_curvep)>*retpletunsafe_from_coordinatesuv=with_label~label:"Edwards.unsafe_from_coordinates"(pairuv|>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_u=get_u_coordinatepointinletp_v=get_v_coordinatepointin(* if b = 1, return (p_u, p_v); otherwise the zero point (0, 1) *)letb=scalar_of_boolbinlet*u=Num.mulbp_uinlet*v=Num.custom~qr:mone~qc:one~qm:onep_vbinret@@pairuvletscalar_mulsp=let*one=Bool.constant_booltrueinwith_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.constant_booltrueinwith_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))endmoduleJubjub=MakeAffine(structleta=moneletd=S.of_string"19257038036680949359750312669786877991949435402254120286184196891950884077233"letscalar_order=Z.of_string"6554484396890773809930967563523245729705921265872317281365359162392183254199"letbase_order=Z.of_string"52435875175126190479447740508185965837690552500527637822603658699938581184513"end)