12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019typeerror=[|`Invalid_format|`Invalid_length|`Invalid_range|`Not_on_curve|`At_infinity|`Low_order]leterror_to_string=function|`Invalid_format->"invalid format"|`Not_on_curve->"point is not on curve"|`At_infinity->"point is at infinity"|`Invalid_length->"invalid length"|`Invalid_range->"invalid range"|`Low_order->"low order"letpp_errorfmte=Format.fprintffmt"Cannot parse point: %s"(error_to_stringe)exceptionMessage_too_longletbit_atbufi=letbyte_num=i/8inletbit_num=imod8inletbyte=Cstruct.get_uint8bufbyte_numinbyteland(1lslbit_num)<>0moduletypeDh=sigtypesecretvalsecret_of_cs:?compress:bool->Cstruct.t->(secret*Cstruct.t,error)resultvalgen_key:?compress:bool->?g:Mirage_crypto_rng.g->unit->secret*Cstruct.tvalkey_exchange:secret->Cstruct.t->(Cstruct.t,error)resultendmoduletypeDsa=sigtypeprivtypepubvalbyte_length:intvalpriv_of_cstruct:Cstruct.t->(priv,error)resultvalpriv_to_cstruct:priv->Cstruct.tvalpub_of_cstruct:Cstruct.t->(pub,error)resultvalpub_to_cstruct:?compress:bool->pub->Cstruct.tvalpub_of_priv:priv->pubvalgenerate:?g:Mirage_crypto_rng.g->unit->priv*pubvalsign:key:priv->?k:Cstruct.t->Cstruct.t->Cstruct.t*Cstruct.tvalverify:key:pub->Cstruct.t*Cstruct.t->Cstruct.t->boolmoduleK_gen(H:Mirage_crypto.Hash.S):sigvalgenerate:key:priv->Cstruct.t->Cstruct.tendendmoduletypeDh_dsa=sigmoduleDh:DhmoduleDsa:DsaendmoduletypeParameters=sigvala:Cstruct.tvalb:Cstruct.tvalg_x:Cstruct.tvalg_y:Cstruct.tvalp:Cstruct.tvaln:Cstruct.tvalpident:Cstruct.tvalbyte_length:intvalfe_length:intvalfirst_byte_bits:intoptionendtypefield_element=Cstruct.buffertypepoint={f_x:field_element;f_y:field_element;f_z:field_element}typescalar=ScalarofCstruct.tmoduletypeForeign=sigvalmul:field_element->field_element->field_element->unitvalsub:field_element->field_element->field_element->unitvaladd:field_element->field_element->field_element->unitvalto_montgomery:field_element->unitvalfrom_bytes_buf:field_element->Cstruct.buffer->unitvalset_one:field_element->unitvalnz:field_element->boolvalsqr:field_element->field_element->unitvalfrom_montgomery:field_element->unitvalto_bytes_buf:Cstruct.buffer->field_element->unitvalinv:field_element->field_element->unitvalselect_c:field_element->bool->field_element->field_element->unitvaldouble_c:point->point->unitvaladd_c:point->point->point->unitendmoduletypeField_element=sigvalcreate:unit->field_elementvalcopy:field_element->field_element->unitvalone:unit->field_elementvalto_bytes:Cstruct.t->field_element->unitvalfrom_montgomery:field_element->unitvaladd:field_element->field_element->field_element->unitvalsub:field_element->field_element->field_element->unitvalmul:field_element->field_element->field_element->unitvalnz:field_element->boolvalsqr:field_element->field_element->unitvalinv:field_element->field_element->unitvalfrom_be_cstruct:Cstruct.t->field_elementvalselect:bool->then_:field_element->else_:field_element->field_elementendmoduleMake_field_element(P:Parameters)(F:Foreign):Field_element=structincludeFletcreate()=Cstruct.to_bigarray(Cstruct.createP.fe_length)letcopydstsrc=Bigarray.Array1.blitsrcdstletchecked_buffercs=assert(Cstruct.lengthcs=P.byte_length);Cstruct.to_bigarraycsletfrom_bytesfecs=F.from_bytes_buffe(checked_buffercs)letone()=letfe=create()inF.set_onefe;feletto_bytescsfe=F.to_bytes_buf(checked_buffercs)feletfrom_be_cstructcs=letcs_rev=Cstruct.revcsinletfe=create()infrom_bytesfecs_rev;F.to_montgomeryfe;feletselectbit~then_~else_=letout=create()inF.select_coutbitthen_else_;outendmoduletypePoint=sigvalat_infinity:unit->pointvalis_infinity:point->boolvaladd:point->point->pointvaldouble:point->pointvalof_cstruct:Cstruct.t->(point,error)resultvalto_cstruct:compress:bool->point->Cstruct.tvalto_affine_raw:point->(field_element*field_element)optionvalx_of_finite_point:point->Cstruct.tvalparams_g:pointvalselect:bool->then_:point->else_:point->pointendmoduleMake_point(P:Parameters)(F:Foreign):Point=structmoduleFe=Make_field_element(P)(F)letat_infinity()=letf_x=Fe.one()inletf_y=Fe.one()inletf_z=Fe.create()in{f_x;f_y;f_z}letis_infinityp=not(Fe.nzp.f_z)letis_solution_to_curve_equation=leta=Fe.from_be_cstructP.ainletb=Fe.from_be_cstructP.binfun~x~y->letx3=Fe.create()inFe.mulx3xx;Fe.mulx3x3x;letax=Fe.create()inFe.mulaxax;lety2=Fe.create()inFe.muly2yy;letsum=Fe.create()inFe.addsumx3ax;Fe.addsumsumb;Fe.subsumsumy2;not(Fe.nzsum)letcheck_coordinatecs=(* ensure cs < p: *)matchEqaf_cstruct.compare_be_with_len~len:P.byte_lengthcsP.p>=0with|true->None|exceptionInvalid_argument_->None|false->Some(Fe.from_be_cstructcs)(** Convert cstruct coordinates to a finite point ensuring:
- x < p
- y < p
- y^2 = ax^3 + ax + b
*)letvalidate_finite_point~x~y=match(check_coordinatex,check_coordinatey)with|Somef_x,Somef_y->ifis_solution_to_curve_equation~x:f_x~y:f_ythenletf_z=Fe.one()inOk{f_x;f_y;f_z}elseError`Not_on_curve|_->Error`Invalid_rangeletto_affine_rawp=ifis_infinitypthenNoneelseletz1=Fe.create()inletz2=Fe.create()inFe.copyz1p.f_z;Fe.from_montgomeryz1;Fe.invz2z1;Fe.sqrz1z2;Fe.from_montgomeryz1;letx=Fe.create()inFe.copyxp.f_x;Fe.mulxxz1;lety=Fe.create()inFe.copyyp.f_y;Fe.mulz1z1z2;Fe.mulyyz1;Some(x,y)letto_affinep=matchto_affine_rawpwith|None->None|Some(x,y)->letout_x=Cstruct.createP.byte_lengthinletout_y=Cstruct.createP.byte_lengthinFe.to_bytesout_xx;Fe.to_bytesout_yy;Some(out_x,out_y)letto_cstruct~compressp=letbuf=matchto_affinepwith|None->Cstruct.create1|Some(x,y)->letfour=Cstruct.create1inCstruct.set_uint8four04;letrev_x=Cstruct.revxandrev_y=Cstruct.revyinCstruct.concat[four;rev_x;rev_y]inifcompressthenletout=Cstruct.create(P.byte_length+1)inletident=2+(Cstruct.get_uint8buf((P.byte_length*2)-1))land1inCstruct.blitbuf1out1P.byte_length;Cstruct.set_uint8out0ident;outelsebufletdoublep=letout={f_x=Fe.create();f_y=Fe.create();f_z=Fe.create()}inF.double_coutp;outletaddfe_pfe_q=letout={f_x=Fe.create();f_y=Fe.create();f_z=Fe.create()}inF.add_coutfe_pfe_q;outletx_of_finite_pointp=matchto_affinepwithNone->assertfalse|Some(x,_)->Cstruct.revxletparams_g=matchvalidate_finite_point~x:P.g_x~y:P.g_ywith|Okp->p|Error_->assertfalseletselectbit~then_~else_={f_x=Fe.selectbit~then_:then_.f_x~else_:else_.f_x;f_y=Fe.selectbit~then_:then_.f_y~else_:else_.f_y;f_z=Fe.selectbit~then_:then_.f_z~else_:else_.f_z;}letpow=letmultab=letr=Fe.create()inFe.mulrab;rinletsqrx=letr=Fe.create()inFe.sqrrx;rinfunxexp->letr0=ref(Fe.one())inletr1=refxinfori=P.byte_length*8-1downto0doletbit=bit_atexpiinletmultiplied=mult!r0!r1inletr0_sqr=sqr!r0inletr1_sqr=sqr!r1inr0:=Fe.selectbit~then_:multiplied~else_:r0_sqr;r1:=Fe.selectbit~then_:r1_sqr~else_:multiplied;done;!r0letdecompress=(* When p = 4*k+3, as is the case of NIST-P256, there is an efficient square
root algorithm to recover the y, as follows:
Given the compact representation of Q as x,
y2 = x^3 + a*x + b
y' = y2^((p+1)/4)
y = min(y',p-y')
Q=(x,y) is the canonical representation of the point
*)letpident=P.pident(* (Params.p + 1) / 4*)inleta=Fe.from_be_cstructP.ainletb=Fe.from_be_cstructP.binletp=Fe.from_be_cstructP.pinfunpk_cstruct->letx=Fe.from_be_cstruct(Cstruct.subpk_cstruct1P.byte_length)inletx3=Fe.create()inletax=Fe.create()inletsum=Fe.create()inFe.mulx3xx;Fe.mulx3x3x;(* x3 *)Fe.mulaxax;(* ax *)Fe.addsumx3ax;Fe.addsumsumb;(* y^2 *)lety=powsumpidentin(* https://tools.ietf.org/id/draft-jivsov-ecc-compact-00.xml#sqrt point 4.3*)lety'=Fe.create()inFe.suby'py;lety_struct=Cstruct.create(P.byte_length)inFe.from_montgomeryy;Fe.to_bytesy_structy;(* number must not be in montgomery domain*)lety_struct=Cstruct.revy_structinlety_struct2=Cstruct.create(P.byte_length)inFe.from_montgomeryy';Fe.to_bytesy_struct2y';(* number must not be in montgomery domain*)lety_struct2=Cstruct.revy_struct2inletident=Cstruct.get_uint8pk_cstruct0inletsignY=2+(Cstruct.get_uint8y_struct(P.byte_length-2))land1inletres=ifInt.equalsignYidenttheny_structelsey_struct2inletout=Cstruct.create((P.byte_length*2)+1)inCstruct.set_uint8out04;Cstruct.blitpk_cstruct1out1P.byte_length;Cstruct.blitres0out(P.byte_length+1)P.byte_length;outletof_cstructcs=letlen=P.byte_lengthinifCstruct.lengthcs=0thenError`Invalid_formatelseletof_cscs=letx=Cstruct.subcs1leninlety=Cstruct.subcs(1+len)leninvalidate_finite_point~x~yinmatchCstruct.get_uint8cs0with|0x00whenCstruct.lengthcs=1->Ok(at_infinity())|0x02|0x03whenCstruct.lengthP.pident>0->letdecompressed=decompresscsinof_csdecompressed|0x04whenCstruct.lengthcs=1+len+len->of_cscs|0x00|0x04->Error`Invalid_length|_->Error`Invalid_formatendmoduletypeScalar=sigvalnot_zero:Cstruct.t->boolvalis_in_range:Cstruct.t->boolvalof_cstruct:Cstruct.t->(scalar,error)resultvalto_cstruct:scalar->Cstruct.tvalscalar_mult:scalar->point->pointendmoduleMake_scalar(Param:Parameters)(P:Point):Scalar=structletnot_zero=letzero=Cstruct.createParam.byte_lengthinfuncs->not(Eqaf_cstruct.equalcszero)letis_in_rangecs=not_zerocs&&Eqaf_cstruct.compare_be_with_len~len:Param.byte_lengthParam.ncs>0letof_cstructcs=matchis_in_rangecswith|exceptionInvalid_argument_->Error`Invalid_length|true->Ok(Scalar(Cstruct.revcs))|false->Error`Invalid_rangeletto_cstruct(Scalarcs)=Cstruct.revcsletscalar_mult(Scalars)p=letr0=ref(P.at_infinity())inletr1=refpinfori=Param.byte_length*8-1downto0doletbit=bit_atsiinletsum=P.add!r0!r1inletr0_double=P.double!r0inletr1_double=P.double!r1inr0:=P.selectbit~then_:sum~else_:r0_double;r1:=P.selectbit~then_:r1_double~else_:sumdone;!r0endmoduleMake_dh(Param:Parameters)(P:Point)(S:Scalar):Dh=structletpoint_of_csc=matchP.of_cstructcwith|Okpwhennot(P.is_infinityp)->Okp|Ok_->Error`At_infinity|Error_ase->eletpoint_to_cs=P.to_cstructtypesecret=scalarletshare?(compress=false)private_key=letpublic_key=S.scalar_multprivate_keyP.params_ginpoint_to_cs~compresspublic_keyletsecret_of_cs?compresss=matchS.of_cstructswith|Okp->Ok(p,share?compressp)|Error_ase->eletrecgenerate_private_key?g()=letcandidate=Mirage_crypto_rng.generate?gParam.byte_lengthinmatchS.of_cstructcandidatewith|Oksecret->secret|Error_->generate_private_key?g()letgen_key?compress?g()=letprivate_key=generate_private_key?g()in(private_key,share?compressprivate_key)letkey_exchangesecretreceived=matchpoint_of_csreceivedwith|Error_aserr->err|Okshared->Ok(P.x_of_finite_point(S.scalar_multsecretshared))endmoduletypeForeign_n=sigvalmul:field_element->field_element->field_element->unitvaladd:field_element->field_element->field_element->unitvalinv:field_element->field_element->unitvalone:field_element->unitvalfrom_bytes:field_element->Cstruct.buffer->unitvalto_bytes:Cstruct.buffer->field_element->unitvalfrom_montgomery:field_element->field_element->unitvalto_montgomery:field_element->field_element->unitendmoduleMake_dsa(Param:Parameters)(F:Foreign_n)(P:Point)(S:Scalar)(H:Mirage_crypto.Hash.S)=structletcreate()=Cstruct.to_bigarray(Cstruct.createParam.fe_length)typepriv=scalarletbyte_length=Param.byte_lengthletpriv_of_cstruct=S.of_cstructletpriv_to_cstruct=S.to_cstructletpaddedmsg=letl=Cstruct.lengthmsginletbl=Param.byte_lengthinletfirst_byte_ok()=matchParam.first_byte_bitswith|None->true|Somem->(Cstruct.get_uint8msg0)land(0xFFland(lnotm))=0inifl>bl||(l=bl&¬(first_byte_ok()))thenraiseMessage_too_longelseifl=blthenmsgelseCstruct.append(Cstruct.create(bl-l))msgletfrom_be_cstructv=letv'=create()inF.from_bytesv'(Cstruct.to_bigarray(Cstruct.revv));v'letto_be_cstructv=letcs=Cstruct.createParam.byte_lengthinF.to_bytes(Cstruct.to_bigarraycs)v;Cstruct.revcs(* RFC 6979: compute a deterministic k *)moduleK_gen(H:Mirage_crypto.Hash.S)=structletdrbg:'aMirage_crypto_rng.generator=letmoduleM=Mirage_crypto_rng.Hmac_drbg(H)in(moduleM)letg~keycs=letg=Mirage_crypto_rng.create~strict:truedrbginMirage_crypto_rng.reseed~g(Cstruct.append(S.to_cstructkey)cs);g(* take qbit length, and ensure it is suitable for ECDSA (> 0 & < n) *)letgeng=letrecgo()=letr=Mirage_crypto_rng.generate~gParam.byte_lengthinifS.is_in_rangerthenrelsego()ingo()letgenerate~keycs=gen(g~key(paddedcs))endmoduleK_gen_default=K_gen(H)typepub=pointletpub_of_cstruct=P.of_cstructletpub_to_cstruct?(compress=false)pk=P.to_cstruct~compresspkletgenerate?g()=(* FIPS 186-4 B 4.2 *)letd=letrecone()=matchS.of_cstruct(Mirage_crypto_rng.generate?gParam.byte_length)with|Okx->x|Error_->one()inone()inletq=S.scalar_multdP.params_gin(d,q)letx_of_finite_point_mod_np=matchP.to_affine_rawpwith|None->None|Some(x,_)->F.to_montgomeryxx;leto=create()inF.oneo;F.mulxxo;F.from_montgomeryxx;Some(to_be_cstructx)letsign~key?kmsg=letmsg=paddedmsginlete=from_be_cstructmsginletg=K_gen_default.g~keymsginletrecdo_signg=letagain()=matchkwith|None->do_signg|Some_->invalid_arg"k not suitable"inletk'=matchkwithNone->K_gen_default.geng|Somek->kinletksc=matchS.of_cstructk'with|Okksc->ksc|Error_->invalid_arg"k not in range"(* if no k is provided, this cannot happen since K_gen_*.gen already preserves the Scalar invariants *)inletpoint=S.scalar_multkscP.params_ginmatchx_of_finite_point_mod_npointwith|None->again()|Somer->letr_mon=from_be_cstructrinF.to_montgomeryr_monr_mon;letkinv=create()inletkmon=from_be_cstructk'inF.to_montgomerykmonkmon;F.invkinvkmon;F.to_montgomerykmonkinv;letrd=create()inletdmon=from_be_cstruct(S.to_cstructkey)inF.to_montgomerydmondmon;F.mulrdr_mondmon;letcmon=create()inletzmon=create()inF.to_montgomeryzmone;F.addcmonzmonrd;letsmon=create()inF.mulsmonkmoncmon;lets=create()inF.from_montgomeryssmon;lets=to_be_cstructsinifS.not_zeros&&S.not_zerorthenr,selseagain()indo_signgletpub_of_privpriv=S.scalar_multprivP.params_gletverify~key(r,s)msg=tryletr=paddedrands=paddedsinifnot(S.is_in_ranger&&S.is_in_ranges)thenfalseelseletmsg=paddedmsginletz=from_be_cstructmsginlets_inv=create()inlets_mon=from_be_cstructsinF.to_montgomerys_mons_mon;F.invs_invs_mon;letu1=create()inF.to_montgomerys_invs_inv;F.to_montgomeryzz;F.mulu1zs_inv;letu2=create()inletr_mon=from_be_cstructrinF.to_montgomeryr_monr_mon;F.mulu2r_mons_inv;F.from_montgomeryu1u1;F.from_montgomeryu2u2;matchS.of_cstruct(to_be_cstructu1),S.of_cstruct(to_be_cstructu2)with|Oku1,Oku2->letpoint=P.add(S.scalar_multu1P.params_g)(S.scalar_multu2key)inbeginmatchx_of_finite_point_mod_npointwith|None->false(* point is infinity *)|Somer'->Cstruct.equalrr'end|Error_,_|_,Error_->falsewith|Message_too_long->falseendmoduleP224:Dh_dsa=structmoduleParams=structleta=Cstruct.of_hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE"letb=Cstruct.of_hex"B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4"letg_x=Cstruct.of_hex"B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"letg_y=Cstruct.of_hex"BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"letp=Cstruct.of_hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001"letn=Cstruct.of_hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D"letpident=Cstruct.emptyletbyte_length=28letfe_length=ifSys.word_size==64then32else28(* TODO: is this congruent with C code? *)letfirst_byte_bits=NoneendmoduleForeign=structexternalmul:field_element->field_element->field_element->unit="mc_p224_mul"[@@noalloc]externalsub:field_element->field_element->field_element->unit="mc_p224_sub"[@@noalloc]externaladd:field_element->field_element->field_element->unit="mc_p224_add"[@@noalloc]externalto_montgomery:field_element->unit="mc_p224_to_montgomery"[@@noalloc]externalfrom_bytes_buf:field_element->Cstruct.buffer->unit="mc_p224_from_bytes"[@@noalloc]externalset_one:field_element->unit="mc_p224_set_one"[@@noalloc]externalnz:field_element->bool="mc_p224_nz"[@@noalloc]externalsqr:field_element->field_element->unit="mc_p224_sqr"[@@noalloc]externalfrom_montgomery:field_element->unit="mc_p224_from_montgomery"[@@noalloc]externalto_bytes_buf:Cstruct.buffer->field_element->unit="mc_p224_to_bytes"[@@noalloc]externalinv:field_element->field_element->unit="mc_p224_inv"[@@noalloc]externalselect_c:field_element->bool->field_element->field_element->unit="mc_p224_select"[@@noalloc]externaldouble_c:point->point->unit="mc_p224_point_double"[@@noalloc]externaladd_c:point->point->point->unit="mc_p224_point_add"[@@noalloc]endmoduleForeign_n=structexternalmul:field_element->field_element->field_element->unit="mc_np224_mul"[@@noalloc]externaladd:field_element->field_element->field_element->unit="mc_np224_add"[@@noalloc]externalinv:field_element->field_element->unit="mc_np224_inv"[@@noalloc]externalone:field_element->unit="mc_np224_one"[@@noalloc]externalfrom_bytes:field_element->Cstruct.buffer->unit="mc_np224_from_bytes"[@@noalloc]externalto_bytes:Cstruct.buffer->field_element->unit="mc_np224_to_bytes"[@@noalloc]externalfrom_montgomery:field_element->field_element->unit="mc_np224_from_montgomery"[@@noalloc]externalto_montgomery:field_element->field_element->unit="mc_np224_to_montgomery"[@@noalloc]endmoduleP=Make_point(Params)(Foreign)moduleS=Make_scalar(Params)(P)moduleDh=Make_dh(Params)(P)(S)moduleDsa=Make_dsa(Params)(Foreign_n)(P)(S)(Mirage_crypto.Hash.SHA256)endmoduleP256:Dh_dsa=structmoduleParams=structleta=Cstruct.of_hex"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC"letb=Cstruct.of_hex"5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"letg_x=Cstruct.of_hex"6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"letg_y=Cstruct.of_hex"4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"letp=Cstruct.of_hex"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"letn=Cstruct.of_hex"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"letpident=Cstruct.of_hex"3FFFFFFFC0000000400000000000000000000000400000000000000000000000"|>Cstruct.rev(* (Params.p + 1) / 4*)letbyte_length=32letfe_length=32letfirst_byte_bits=NoneendmoduleForeign=structexternalmul:field_element->field_element->field_element->unit="mc_p256_mul"[@@noalloc]externalsub:field_element->field_element->field_element->unit="mc_p256_sub"[@@noalloc]externaladd:field_element->field_element->field_element->unit="mc_p256_add"[@@noalloc]externalto_montgomery:field_element->unit="mc_p256_to_montgomery"[@@noalloc]externalfrom_bytes_buf:field_element->Cstruct.buffer->unit="mc_p256_from_bytes"[@@noalloc]externalset_one:field_element->unit="mc_p256_set_one"[@@noalloc]externalnz:field_element->bool="mc_p256_nz"[@@noalloc]externalsqr:field_element->field_element->unit="mc_p256_sqr"[@@noalloc]externalfrom_montgomery:field_element->unit="mc_p256_from_montgomery"[@@noalloc]externalto_bytes_buf:Cstruct.buffer->field_element->unit="mc_p256_to_bytes"[@@noalloc]externalinv:field_element->field_element->unit="mc_p256_inv"[@@noalloc]externalselect_c:field_element->bool->field_element->field_element->unit="mc_p256_select"[@@noalloc]externaldouble_c:point->point->unit="mc_p256_point_double"[@@noalloc]externaladd_c:point->point->point->unit="mc_p256_point_add"[@@noalloc]endmoduleForeign_n=structexternalmul:field_element->field_element->field_element->unit="mc_np256_mul"[@@noalloc]externaladd:field_element->field_element->field_element->unit="mc_np256_add"[@@noalloc]externalinv:field_element->field_element->unit="mc_np256_inv"[@@noalloc]externalone:field_element->unit="mc_np256_one"[@@noalloc]externalfrom_bytes:field_element->Cstruct.buffer->unit="mc_np256_from_bytes"[@@noalloc]externalto_bytes:Cstruct.buffer->field_element->unit="mc_np256_to_bytes"[@@noalloc]externalfrom_montgomery:field_element->field_element->unit="mc_np256_from_montgomery"[@@noalloc]externalto_montgomery:field_element->field_element->unit="mc_np256_to_montgomery"[@@noalloc]endmoduleP=Make_point(Params)(Foreign)moduleS=Make_scalar(Params)(P)moduleDh=Make_dh(Params)(P)(S)moduleDsa=Make_dsa(Params)(Foreign_n)(P)(S)(Mirage_crypto.Hash.SHA256)endmoduleP384:Dh_dsa=structmoduleParams=structleta=Cstruct.of_hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC"letb=Cstruct.of_hex"B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF"letg_x=Cstruct.of_hex"AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"letg_y=Cstruct.of_hex"3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f"letp=Cstruct.of_hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF"letn=Cstruct.of_hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"letpident=Cstruct.of_hex"3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFC00000000000000040000000"|>Cstruct.rev(* (Params.p + 1) / 4*)letbyte_length=48letfe_length=48letfirst_byte_bits=NoneendmoduleForeign=structexternalmul:field_element->field_element->field_element->unit="mc_p384_mul"[@@noalloc]externalsub:field_element->field_element->field_element->unit="mc_p384_sub"[@@noalloc]externaladd:field_element->field_element->field_element->unit="mc_p384_add"[@@noalloc]externalto_montgomery:field_element->unit="mc_p384_to_montgomery"[@@noalloc]externalfrom_bytes_buf:field_element->Cstruct.buffer->unit="mc_p384_from_bytes"[@@noalloc]externalset_one:field_element->unit="mc_p384_set_one"[@@noalloc]externalnz:field_element->bool="mc_p384_nz"[@@noalloc]externalsqr:field_element->field_element->unit="mc_p384_sqr"[@@noalloc]externalfrom_montgomery:field_element->unit="mc_p384_from_montgomery"[@@noalloc]externalto_bytes_buf:Cstruct.buffer->field_element->unit="mc_p384_to_bytes"[@@noalloc]externalinv:field_element->field_element->unit="mc_p384_inv"[@@noalloc]externalselect_c:field_element->bool->field_element->field_element->unit="mc_p384_select"[@@noalloc]externaldouble_c:point->point->unit="mc_p384_point_double"[@@noalloc]externaladd_c:point->point->point->unit="mc_p384_point_add"[@@noalloc]endmoduleForeign_n=structexternalmul:field_element->field_element->field_element->unit="mc_np384_mul"[@@noalloc]externaladd:field_element->field_element->field_element->unit="mc_np384_add"[@@noalloc]externalinv:field_element->field_element->unit="mc_np384_inv"[@@noalloc]externalone:field_element->unit="mc_np384_one"[@@noalloc]externalfrom_bytes:field_element->Cstruct.buffer->unit="mc_np384_from_bytes"[@@noalloc]externalto_bytes:Cstruct.buffer->field_element->unit="mc_np384_to_bytes"[@@noalloc]externalfrom_montgomery:field_element->field_element->unit="mc_np384_from_montgomery"[@@noalloc]externalto_montgomery:field_element->field_element->unit="mc_np384_to_montgomery"[@@noalloc]endmoduleP=Make_point(Params)(Foreign)moduleS=Make_scalar(Params)(P)moduleDh=Make_dh(Params)(P)(S)moduleDsa=Make_dsa(Params)(Foreign_n)(P)(S)(Mirage_crypto.Hash.SHA384)endmoduleP521:Dh_dsa=structmoduleParams=structleta=Cstruct.of_hex"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC"letb=Cstruct.of_hex"0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00"letg_x=Cstruct.of_hex"00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"letg_y=Cstruct.of_hex"011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650"letp=Cstruct.of_hex"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"letn=Cstruct.of_hex"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409"letpident=Cstruct.of_hex"017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"|>Cstruct.revletbyte_length=66letfe_length=ifSys.word_size==64then72else68(* TODO: is this congruent with C code? *)letfirst_byte_bits=Some0x01endmoduleForeign=structexternalmul:field_element->field_element->field_element->unit="mc_p521_mul"[@@noalloc]externalsub:field_element->field_element->field_element->unit="mc_p521_sub"[@@noalloc]externaladd:field_element->field_element->field_element->unit="mc_p521_add"[@@noalloc]externalto_montgomery:field_element->unit="mc_p521_to_montgomery"[@@noalloc]externalfrom_bytes_buf:field_element->Cstruct.buffer->unit="mc_p521_from_bytes"[@@noalloc]externalset_one:field_element->unit="mc_p521_set_one"[@@noalloc]externalnz:field_element->bool="mc_p521_nz"[@@noalloc]externalsqr:field_element->field_element->unit="mc_p521_sqr"[@@noalloc]externalfrom_montgomery:field_element->unit="mc_p521_from_montgomery"[@@noalloc]externalto_bytes_buf:Cstruct.buffer->field_element->unit="mc_p521_to_bytes"[@@noalloc]externalinv:field_element->field_element->unit="mc_p521_inv"[@@noalloc]externalselect_c:field_element->bool->field_element->field_element->unit="mc_p521_select"[@@noalloc]externaldouble_c:point->point->unit="mc_p521_point_double"[@@noalloc]externaladd_c:point->point->point->unit="mc_p521_point_add"[@@noalloc]endmoduleForeign_n=structexternalmul:field_element->field_element->field_element->unit="mc_np521_mul"[@@noalloc]externaladd:field_element->field_element->field_element->unit="mc_np521_add"[@@noalloc]externalinv:field_element->field_element->unit="mc_np521_inv"[@@noalloc]externalone:field_element->unit="mc_np521_one"[@@noalloc]externalfrom_bytes:field_element->Cstruct.buffer->unit="mc_np521_from_bytes"[@@noalloc]externalto_bytes:Cstruct.buffer->field_element->unit="mc_np521_to_bytes"[@@noalloc]externalfrom_montgomery:field_element->field_element->unit="mc_np521_from_montgomery"[@@noalloc]externalto_montgomery:field_element->field_element->unit="mc_np521_to_montgomery"[@@noalloc]endmoduleP=Make_point(Params)(Foreign)moduleS=Make_scalar(Params)(P)moduleDh=Make_dh(Params)(P)(S)moduleDsa=Make_dsa(Params)(Foreign_n)(P)(S)(Mirage_crypto.Hash.SHA512)endmoduleX25519=struct(* RFC 7748 *)externalx25519_scalar_mult_generic:Cstruct.buffer->Cstruct.buffer->int->Cstruct.buffer->int->unit="mc_x25519_scalar_mult_generic"[@@noalloc]letkey_len=32letscalar_multin_base=letout=Cstruct.createkey_leninx25519_scalar_mult_genericout.Cstruct.bufferin_.Cstruct.bufferin_.Cstruct.offbase.Cstruct.bufferbase.Cstruct.off;outtypesecret=Cstruct.tletbasepoint=letdata=Cstruct.createkey_leninCstruct.set_uint8data09;dataletpublicpriv=scalar_multprivbasepointletgen_key?compress:_?g()=letsecret=Mirage_crypto_rng.generate?gkey_leninsecret,publicsecretletsecret_of_cs?compress:_s=ifCstruct.lengths=key_lenthenOk(s,publics)elseError`Invalid_lengthletis_zero=letzero=Cstruct.createkey_leninfuncs->Cstruct.equalzerocsletkey_exchangesecretpublic=ifCstruct.lengthpublic=key_lenthenletres=scalar_multsecretpublicinifis_zeroresthenError`Low_orderelseOkreselseError`Invalid_lengthendmoduleEd25519=structexternalscalar_mult_base_to_bytes:Cstruct.buffer->Cstruct.buffer->unit="mc_25519_scalar_mult_base"[@@noalloc]externalreduce_l:Cstruct.buffer->unit="mc_25519_reduce_l"[@@noalloc]externalmuladd:Cstruct.buffer->Cstruct.buffer->Cstruct.buffer->Cstruct.buffer->unit="mc_25519_muladd"[@@noalloc]externaldouble_scalar_mult:Cstruct.buffer->Cstruct.buffer->Cstruct.buffer->Cstruct.buffer->int->bool="mc_25519_double_scalar_mult"[@@noalloc]externalpub_ok:Cstruct.buffer->bool="mc_25519_pub_ok"[@@noalloc]typepub=Cstruct.ttypepriv=Cstruct.t(* RFC 8032 *)letkey_len=32letpublicsecret=(* section 5.1.5 *)(* step 1 *)leth=Mirage_crypto.Hash.SHA512.digestsecretin(* step 2 *)lets,rest=Cstruct.splithkey_leninCstruct.set_uint8s0(Cstruct.get_uint8s0land248);Cstruct.set_uint8s31((Cstruct.get_uint8s31land127)lor64);(* step 3 and 4 *)letpublic=Cstruct.createkey_leninscalar_mult_base_to_bytespublic.Cstruct.buffers.Cstruct.buffer;public,(s,rest)letpub_of_privsecret=fst(publicsecret)letpriv_of_cstructcs=ifCstruct.lengthcs=key_lenthenOkcselseError`Invalid_lengthletpriv_to_cstructpriv=privletpub_of_cstructcs=ifCstruct.lengthcs=key_lenthenletcs_copy=Cstruct.createkey_leninCstruct.blitcs0cs_copy0key_len;ifpub_okcs_copy.Cstruct.bufferthenOkcs_copyelseError`Not_on_curveelseError`Invalid_lengthletpub_to_cstructpub=publetgenerate?g()=letsecret=Mirage_crypto_rng.generate?gkey_leninsecret,pub_of_privsecretletsign~keymsg=(* section 5.1.6 *)letpub,(s,prefix)=publickeyinletr=Mirage_crypto.Hash.SHA512.digest(Cstruct.appendprefixmsg)inreduce_lr.Cstruct.buffer;letr_big=Cstruct.createkey_leninscalar_mult_base_to_bytesr_big.Cstruct.bufferr.Cstruct.buffer;letk=Mirage_crypto.Hash.SHA512.digest(Cstruct.concat[r_big;pub;msg])inreduce_lk.Cstruct.buffer;lets_out=Cstruct.createkey_leninmuladds_out.Cstruct.bufferk.Cstruct.buffers.Cstruct.bufferr.Cstruct.buffer;Cstruct.appendr_bigs_outletverify~keysignature~msg=(* section 5.1.7 *)ifCstruct.lengthsignature=2*key_lenthenletr,s=Cstruct.splitsignaturekey_leninlets_smaller_l=(* check s within 0 <= s < L *)lets'=Cstruct.create(key_len*2)inCstruct.blits0s'0key_len;reduce_ls'.Cstruct.buffer;lets''=Cstruct.(appends(createkey_len))inCstruct.equals''s'inifs_smaller_lthenbeginletk=Mirage_crypto.Hash.SHA512.digest(Cstruct.concat[r;key;msg])inreduce_lk.Cstruct.buffer;letr'=Cstruct.createkey_leninletsuccess=double_scalar_multr'.Cstruct.bufferk.Cstruct.bufferkey.Cstruct.buffers.Cstruct.buffers.Cstruct.offinsuccess&&Cstruct.equalrr'endelsefalseelsefalseend