From 56df468a54609f6fa372b93875304c526e96d751 Mon Sep 17 00:00:00 2001 From: Ron Eldor Date: Tue, 8 Aug 2017 11:12:52 +0300 Subject: [PATCH] Alternative ECDSA and ECDH support Add support for Alternative ECDSA and ECDH, on the higher level, over CC310. Note that CC generates ECC keys according to FIPS 186, while mbed TLS generates according to RFC 6979 and RFC 4754, which causes test vectors for curve p521 to fail --- .../TOOLCHAIN_GCC_ARM/libcc_310_core.a | Bin 287272 -> 235890 bytes .../TARGET_CRYPTOCELL310/cc_internal.c | 153 ++++++++ .../TARGET_CRYPTOCELL310/cc_internal.h | 131 +++++++ .../targets/TARGET_CRYPTOCELL310/cc_rand.h | 73 ++++ .../targets/TARGET_CRYPTOCELL310/ecdh_alt.c | 256 ++++++++++++ .../targets/TARGET_CRYPTOCELL310/ecdsa_alt.c | 332 ++++++++++++++++ .../include/crys_common.h | 371 ++++++++++++++++++ .../include/crys_common_error.h | 95 +++++ .../include/crys_ecpki_domain.h | 80 ++++ .../include/ssi_pal_compiler.h | 147 +++++++ .../include/ssi_pka_hw_plat_defs.h | 77 ++++ .../TARGET_CRYPTOCELL310/mbedtls_device.h | 5 + 12 files changed, 1720 insertions(+) create mode 100644 features/mbedtls/targets/TARGET_CRYPTOCELL310/cc_internal.c create mode 100644 features/mbedtls/targets/TARGET_CRYPTOCELL310/cc_internal.h create mode 100644 features/mbedtls/targets/TARGET_CRYPTOCELL310/cc_rand.h create mode 100644 features/mbedtls/targets/TARGET_CRYPTOCELL310/ecdh_alt.c create mode 100644 features/mbedtls/targets/TARGET_CRYPTOCELL310/ecdsa_alt.c create mode 100644 features/mbedtls/targets/TARGET_CRYPTOCELL310/include/crys_common.h create mode 100644 features/mbedtls/targets/TARGET_CRYPTOCELL310/include/crys_common_error.h create mode 100644 features/mbedtls/targets/TARGET_CRYPTOCELL310/include/crys_ecpki_domain.h create mode 100644 features/mbedtls/targets/TARGET_CRYPTOCELL310/include/ssi_pal_compiler.h create mode 100644 features/mbedtls/targets/TARGET_CRYPTOCELL310/include/ssi_pka_hw_plat_defs.h diff --git a/features/mbedtls/targets/TARGET_CRYPTOCELL310/binaries/TOOLCHAIN_GCC_ARM/libcc_310_core.a b/features/mbedtls/targets/TARGET_CRYPTOCELL310/binaries/TOOLCHAIN_GCC_ARM/libcc_310_core.a index 85abc538277a68621eb4a68b05b11019586368dc..4d0d8957775c767b05cfca12cc914127e728bdb5 100644 GIT binary patch delta 52099 zcmbTf3wTpiwm81`IVbP5P2cG|O-rAEY0INLgtQHZ(3ZA5L{P*cjz-5vK}JEHNqDHB z$h0}7Crw%?jyj->7Rrn;f)r#NeBKrr2UN5=Uc;pGNTA>W8TqYsl0uw2_q+e^pYPjU zXYKddd+oK?UTf{sUB~0k?~85Ca89b6FmcM{NhXuUgum#&Ce!4y2@~XKQ?r&3Y9z!I zOGtjl{|uJj5%RxR}kjL>NK<9mc)7=RHN4S$9g9SvUwoP>NC zAjCiQ$07JFA*10c6o?8`@ed*g-CKlWNLlnhgZ&;t|2-^G5{lvB*9d)VStK~&!MXKD zc={niF>HmncE}tZy3P|C9bSgAuR;fUUkir=CkZ|LLO8q!o%&DVi&#Sc`>q?o`H%U8 zj)p7cghF6w0b$f7goztZm=wUXCJ`ooDq%`z5T?AEFjIKKSZfJ0yMZtb^Z)N~FXaDU zg7ZfSt8XLB|DWLelraBWcm`fzH2m^w!u&Wm!x5fig!%Wd6W(q#yz)E3jD~|S8W;{g zOPKeWABU5x2ooJXzn?H)E5qS$TEc{~e;g!d3Sp%G8Q8dc$o~i>w-L7Dq5top`hLRx zUm*oEG}Zol=y9k(_r&ayp`NJ^(pcr#;fh5duF-LS(c%C31IE znlw#uaj^!wgI#HvZKx%t1jk9qnv~XjQnDp2fxq^oPWW4&|7ml}Y;`2PSx&!OPIt)Z z56J1%4)sLZGVH&f^liAGmZ}EKA2X$T;VW5QA5$S z?_T|3)7}aP$p_3{+@~lirk2LwwK6JP`|gKp)OX_G*oMX+RhL77W0GML#*-gZ`~fUv z#wzmceanh-=qM??>f|WC8U82%j!g7XcpBhOM&X#gF$%|YcNC84-Y6W?&qd*w9*n{v zogqubC4Xl##$evXEc}sw;l4Z&g=4x$j8C8$f_kiDTq~dn(B%~XpMokMh~O;%Lx8W2 z;7y5^9VVKFo%%S2(w^( zpikO-Lb4IU9$SJC@+}3(jDh+PLVb55Od-S(f!_dx`tKyM96Ue+W`uc!jE%ra2%(|r z2%#YdLTF$;!hAxy0Ad3@2%&)&5kdpIBCr=4$To>RGq?)j=7lSmJ)9Vv%H?rtLL^~u zOCB8(25%~azhx_PMC)=+4Uf5&LK-K=?`Knm)(!E(N=qSgN+Z1Wd;xt@IBF>roAVZlb#^agw&M7l?^J1iRP8uC8*1rwR)b8dFrls-eBolRbE8dc)mjDt~fhN zW(8vF%k08FX+oZ2w3c;oOsY^h)y>^~pYIOgqp1zbWPUU6$ra4g9?!4lPlODl$fnti zbY097vxzt4;j@Cz<+)HjF_`=Mr*Tvn!>90-w!ZhKFQYN1B$t8YG3LA#%kMG^6K5RJ zwo6Z06kcLVY!QB#QBbsr@8I|Jc1tH(CUi~e?v{p{DL>W22#VHfo)sVApFd|IT!(U( zP(RbiP4QN~DmZ42&&4E#h z;VlRIF1qeif4thx^d3GJe1;Y=gAg2J3t!9`Z^Cj+|X^#1`zLY-iw@P$qWKbQX%+OEW z%;yp@R0kO-;mV^$fSINY9Fr^$;*-$O#5a;LUpFuF9|+O7q=5`a=G?`8T9P@CK6j!2 zm{hbBUuEo*f5K;p^gx%sN)zYjbkE(95*4ZW3gP zR?|Ps>0vtx#xX1S{t&02Zc;>oFS+PA^BUE_@-@u3>Hsw}13T9MtnMf4t$!zv*XKHD zXuoQPL(!qweo1xZPmeZqTvqgu?enA(7a8vySOqxK(s7yXZ45lqaD+Alv{T6ThJY%z z!5LIH=!cb=bAr|-4FTPxIRTYsGSBlv{2{(ENMeslrXtulo$BSlOoRd{=e( zPo$`3V2R_Hb+=Vp^PY6t)akg*vDpmQt|+b?wH7*R1C;(z zI&FY%7djzxORmFE0dNQ!>eYpMwVy&msy0>Ue?ddFs$aVb2 zpXPurKy`Ow(@@)v2>eop@B4ds>MK16EEHMBFB$$GKk?D+OlLVy7Y(!V`duWC?bZu1 zLaY!c7=(CP5~<+HxP(`XM+|wnj*pGh%u2?wFw9J%LnCN>pTRKeUrpEr^S27B1s}6IDUAk?;{6{v9W-HjYx-ptejdTJmxe{@sk{U{NL`}y1HQ31UulB~m zs?qEsxf{({GWFN*rDL^&lYM;`oe%5I)CeCxHqE)^NMn$TZ49!pQ+UNNqmBuUAtn6l znQSOd7qsE)l)S2WWgsofHqlG+CUh#K4bw4}^-c6%D{Ty9WT=2;-h3vVaqoNkf+{bu zret@OzO1N1mua|tgWQe zg{;TlrY_;D$5YLqZXntiLSm6Yg3y((w&6PD7Tup$kIJhRUW_m3= z%34f$Ypvk;MQu{LhYK0mX|~3oI#v}j>WNv=D!lWH@u^QdKIQQ% zkF!^_7vy>#PprxG!jqtL9+QWwZ_v3an#ZPcFKpLlNp8@#MKFzaFQ0I#fh5Pd{gs?w<6oE4! zi#Can`UsqlFqx3MA`oAUNhPEOA)Gs2!FZ_W6NFIDw-J~G&0;<22%$W_FqRvOFpX%* zQcQq?cMCCFd>}vUT$nF>xTTPq#9RdhAk6zREC47>um)0vs$25tWO1c}hWGy#Vds~H ziWgyQ7mIBV(|kO7z<~)WCd44Fw9`x>W@|~*{+-HAo;V>)TOMKE*2D?K9NeGCC-K%x zS0B^QWh&>8@xW`@5M_UNq={3d8nNt;t6$$c#-WfmBO(yFulZ%Oq+F8k*i1M%o(fcspJ_1# zXA-N0D^t&7WN21!>#SKLWMXWnS2f+C zXjjNNKayNcm>P~%wkx~7aYCgSy@SpUY^Z_6-kRXnhK3O`10)D8&!G}j^8167Fodb$ zShb**W7|25w*|M`uv*&)nP3a3IjBBrdv7g<`mJ}JrlEVd*=6xCPnodi(b(84^atv2 zHU<_ZaYyI`i~_lUO?PPBTJK5d7KmN_=?Q4>&WYlEhFRHz!^%EFzG6XN8Kz6E9Q1(Ka- zYlHpu^&`^s75pAP3j}cN5WW)}=;W-lY~?J-+H`*KCpYnKh6At5Myr*QsG4;GZtW>2tST`%r)luPHF+=(5YM2X? z5D?dJ1dc(%J)VNHWSG7F);RtQ$jaG#7m2PbOoS%aje5B0M}@;4A9S$LAuR2DD+N1^ zvS(N+*s?#f{wZK7eHO2o>X9&p`bh~B(CdX|zQ2xlbzkmn>At+b9|lf2(V^U?l!xuK z)Y_yD^~M4tYgTor;OKGrPrDmV2tVuEtK@^*=Wrdu*zRhjeFXG09l~mO~D z+XRoKR?#7R-TiE3UGQrVTVgfT*AUo}T@%n(HUx7UShgX+#uC#;{!xBT@asADAh(zk z=8Q;F>;bB-9g(IAFK+KiKf+C`sR`yUs2Snl4B@gconv5`<<@W>VcCxLS^{*JR#O$s zpC<%%ycsP3EObVz0bzq8n_y22|ERn_;aPYT$8;$Q$Ng&|>|^0ySU6Z5g=4xW3dizY zQ8=VK$v06EnBiO$4k9M`E8wUEWI(2n8^q01{)HPvecdRI>ARwEtZ#o5j_Jpva23fT zf{NED9g z-)P{E{FA%kBTS?vKLpakVaz36@Z(Ourh1tH|9D zqlX~>!ZYED!m)ylQ8-r6iqj|m!X4;}!sQMcew^+yhy$P!1IcpJ+)=f#1F~!el0$Vc zN|kE>!dZ|sNARZsE&&R$MQ{ONH{kUV{AGZ52p3;$tokiXGst*yEiq8TyMTWVIkDDU zz+ZxCzZ)Rp69H;qK1OSu3;0~&sh4t`yCHV8?q5ReMZiZQweAM|uP{j;MDRZV{#$s_ z;}QHbz}Lc{;%j3os8QbxIKC6&sBWS#h8rVz4D{|Pz>N?u_Y!Phq`Pm-%l9(!vSp@6 zR8;_R86u9$4I!>7gp=ScwbKZhfv`HPna6n4W^3W~o;#z2#o+CzmrtrLv45&V1f-ZKtVe~DAw9LZn87NOa6}P|hKB$r)id5f%vDyMIOR7OGy!(-`2;Q3Ru=720?cjTd{G zxD?T{n8rt*g&-dpX~N2e40=lV@YQIc-Po7BC;qx_xuCDnENW5 z+MLNN_-(ysrH!t8vaS4h8x>Odv(l5T*o)tNfALawAIVb>tF%7e)WuEK44HUtcZvK~ zeY3{ek_LQNp1aV*v%5JnD=V4od=)>H=U&C~sOJzYZ&k(wU1*U^%gD;fRX-~H?5$kT zr;2Z7EppTud5x^XY7ESdjU85UHrt+R?#zno@k+tyduLdoh0~FSYx`(eOBJmrhAGty z$C4zu8%e$meW^YZ&tBa8)7$x^&SbBkJu;)bjIZT6pJ#UeL8b4kl-b|6x2o_$w`st))Y zgBG2tJySO0b+IvyyeD6vUm=jlf2N; zM{=B3p1nd_88^F)2pm5jY#uex-xWV7pua~4%lIT8dp^~oU1N~w%mr2|(P__R`1WlYESugKD`)RG?HQAfnrO9B?HN?^L-)&*1Mt3Qio* zhOSv$`;vTCn^PUSR&KGC+t~AQxe3rnyhNSrt2YExY+}o$!35v5zNGLp-aCy?=uGq? z1-agQcUa54xKBB((~z;V2T~-Rg_K$cYk6A04Ph-SGp8Ml<#Vn)eP!XSOQ#p{X_D4L zOH&3)=icg1x<1>SaLozTaWLIU;px72icCGE=%WDzU+q_TrhsZ3n+kDr_4_g1Sui_VvG z<=OKqGw0ZnJ=eZ7{BTX>X&lL3iH&HHC|Zu?Yl4RuFk=S~wF=$GmW&E>1%m1Ajn0k0 z^}|0(KwUw4qVREm_x?N1MY6;0gZV#*!ZH8Qzu~`)Dv$Zm#v1+svn52B`C*n|JzfL~ zk^7EMQ|yG)vBK`-8T3Qp56Ax!4=z7M3!J+t0+$L0|1fjXqmWAr=FgM31HlGuf;P3F zd?`l=4p=sXz|XfMgwkjx)uy0%^jYQ`PIOJ+%!(w~Tw2AIFVTEqFJDNFV!W2i5nM~v z__&`fr1Q`uN?#OnQ$Ss_QTXtWg$f&pEFZ}lMoP2q+;K`@L%d=Uos!(RUaW{S{mo(1`dR@aoW=}?0@jb`sg&S^boi%u)*6G-=bMY zlp!r!Gi&^3lkL9~%HB;Jho|J{&)G?wk8NjQnSCf3TuMP9ekf%Q#mh{bB7o))97a5xpzy(0y|R^qYY&5`f{Liq=x_UGiFoXK0h^Q=DqGG=A^tme$H&o+b#U% z-8s%X?Q>)nxhw*6_ys<2bU1T+1ivi;7eg#Pv)JzUFZ3nu%|5uu{wz)%!6%=&5&>tYAA<29%2)b=BOI+ZJV zQ`r07G&)WA`+FI&t^P&cN3vP>tzO?g&Ml<8ztP~{m+o3(TLgsu!?oQ=-Mij@_BuUB ztV;A{Vebbw&6^%YXh0jp0>l#jQG)oZqbLwE3VC~?a7?d?Dv#;apu!Y10};XMHSsHu z@Wp}EaKt_T;U|mEK@QXpUPTBbr$tc$ipe4c=m#f6@LGgGx+r`hsjfi?`8Gx1D+odF zScIeE~knPOvYkg~J1dLU0Nv zTH0x{@UMYrYBjQxD#}p{?ZkxvKg9$Y6oI6oCOv&%&ZvszH})>+>)e;gC-W-4cedqC zu1_%x2hzN}yPooYXP zPWojE5w`}u%6BabL(WAVpyfF0y7#ezIJI!xo&SGuz~&3NZ~2z zYO0%jT+_ObyBL2TcX8e?xQlU5(zXg415yiV{ZLX5f%MYP$vz#V=!3yK_ZIWqrMLv3 z8y#-2RkJn(h`dENUb?obT{2ABFHKEggHE=sdZT10pHesQFgOK3W2*V-FATdFcbay9 zl>T~f4$lrjC2^!^=OC>Rs-?j+iGjV@E5w|cHjb%ahBq+9d<73(RAI+aY_b|z=iuD&*028~IehFi}wmky*p)4NaFbzddO+Z$Is2dX)& z>lE;{N}f(@41BC1xwor?znyW!QvSVRjrN^kt@f1=qZ97>G{2z0{zw1A0j2(w)LZ<4 zjk~yGId|!JNiPi6lTT1L)3yQ!sYlrJY4#-U(i;idVLeHgXaM zOC~eSu7G|iFr=n1t7?*2Ra2N%ZI)TpnlP(6B!s}ykqPIdld^Ne9f#G1mR0vXIR4?A zZrJgvUSf^H@}bSK*}#uB@v0E3X$*8~1Zl|3P2trZA^WS}kI&{?!Ho#gv>aa&WVLFX zELjk$=I4PVS|Km|=Dlh4auMa%A6y?W^onfyOU(^q-7}0)*z2FAJS>@7z}4WY|K}NY zGJK5Aaag4CrW4t;sQrk^WH2d8j!T?TXg@bzDFUHd6ND4zs`aXh&(z1I>E$m<)vNka z{>sr*axs3bY7)7mSCNof{mzB|QdaO*evVKUCpkvs4M&--p}TD5WSOah>&WI%adsB(g27mn-57XUzbC}$ zHuNfnb!=l`z1Gx7+`>R8Y5pUbW&C#o;GJN#1&QrYb>3;}K@-j2Kjs_^ACBt@ab)Do z*6LYOfmQW+se^zup0cIQtSl@LpB0V(&Rb_rUYov|Y~CkKIzJXpAc`I0^C#Z7A(N7|O-kd?!bHacO>r^z#YV(*ty@4Ej~FvXX* z*9g?HUoMsm6^1LY@~`^8&)jY(gNm@iByUZ&q4bz!WF9?zQZkgWrQAS#DKpR)qB#SD ziM}d+A7L+QS}<>dFS+whb-WZ&<=0=7~6atJohVYN;>tfrgz z@qB`p$vX=C zI?=nxhS*WbKoLJGC6#5vdAS(Q!way}&TG;^P;Q$l9Ny}jL6}|BY4DivR;LZJzH|rY z%YgXAL4{B0&2S_*eCZi+`oVDVWLcghMW+W`{N4U9rG>8L{zOm>Y+RY0l>|ONIa&Cg z$#8rk0;t>^2RY1TY7$of+ZEad}k}tj4COkNjV;I`w z$p6xJYoY?S-B}QXu93yDIbf+&@Ugr`o@Rl$*qXFM(+}^b@#u0nSm8__s4}SV@dWHKh-EiKJy`4G^vj*YG?+m#^z^cMO zO28{YcIh0&VaFyz=w@0W41H&yO+x6qCumIHgVF-(ybW0*6hL(!!c`IYWCU(O2wVRF zgiw(+!V-TGf!h&6xz`W^3q6DoM~xZwMPPpf zz88U~5kdzF@T`M8I|6S*2o1I%gmhN~wnku21olSYA%xg5gwQcE{*kp0t`^?9vL1Zd zs=m)tpw zqF+U?cuGmnUoZYfP(?F-v@x)gCWblf2dLaiRO9i6^4e0dMNjXc-Qu71v{a*QTXtq# zgN4r$bulze^MLCgr%y?l=iV?blE2A;KMI_|vk+<9xzXeB$Wf%OKkzEPb+ zD`-azbflP9UEC-$m<;jt7@F+V?gnY9pSp30orNbQEVGWmQ<8@=xhP{{JoN%zHh*6# zpHp$WMgb0as$A~kN2?fF9d#CRHC}n{hf1FDHD1~B9j2A8f|KPC73I<_V1bp# zuPW%6m*^NZ)Z!RwykM7y7aaqha29J&YYp3Z(NK#+NJM4_nDNLIp7Q_|h@ZvLEGOp2 z$tF8)n8tBH0J*46*V>e7U?=<3LvAgu~_Bwa|qo^nc3$I~v8yp>>A?E$XR4tDHt&I}>r zdQR%aB~mQs)XJ&>#kU1g98tJbkIyE;;GSEqFJ^f&5C`I^m9`_NUqG#I{3L-Mq0Zk& z82E_@{3Ze&$e@95c0}N=2$b&%K>RO|?}ENSwuS)Q8o@gva2fJZh~I<|HioSTfgj5* z{lH&sFbUbQMEq3}ZDV>O%BfaRGzI08{wdjU|CG4%w{WUIB@QOTNk2x`Ou1yul)?(k z)g?1mp$Crpt3g{e>J{|Wem0GrJaLjRZ&9H$(*g}eodrkz7GLVsy1Os;o7hl}y1BlC z+eVeGI(N5ph%^Qk8!NnOLDkk6*u?SyP%=2uZB@aoRhriB%g1}VFP|V_fgffy3VGdw zlM2uhEq0!HT){dL;P0)Ii7tdo@&u)v-~&D@N(&h9uPJqm zlJqfHGw2e8-9&=Mu7l^P!R%l{`yn3^Gsc~iHdzu!Tnm%~bkf;~8$*8%V;%3!0vGGV z7LAXTlHmKU#(=is)nz>E(RR-c_EdxK2ek$i&78X`sICHLqNooVtGQ05M(=_3wVc-I zJhOwQTdM=4Tnk<&vq!keQ)_@9s7m>{d?&AS7x4;NdspEj+o+)2r8>cgacQ(LPJU+# z=gW1}j3{TY;;b}!Gu4S3(&%LMZa5{a;=$MKSQ_;>H9jR$hwACI-a?$ruq zzUSu(mx)#9eu2ieRtGj#7dfhfTdSAB9>}-^iS3PRs~#ccu-;%x8uh9H7GNrJgyTlN zY985#v7KCFU_*9QAXZr?t8l8+v1Fc36XXR%_rH18`)E z+NWwQ_xOOfwW#* z-jOb2?@Fh7#nucuX{pNhE>w9Ve^y79oMV}sKc^!nlK-3DQgn8+WDD88YKfcq`|ACJ z_wZ_8ZBTz(E%@iCgmN$tP3T=+5hHvld0epnUJ&y$>3C2#FUX`1W?SksAx^V>*1Lnn z=#>s$NM^U$I{@RO_ckpSzs;oiDixBsMJL8*(KM&lr}k<*aOccT!3&M%aVFf5wLXhC zCe%n1*1*jTaQW7Fm^MQv+sd`YbW*pXE!Gp)$$?w%;ML}X-Ip6dQKBAD`oI(WCbR9$ z>h$KzgG~NHf1!N3vjPi5YFV`A553799cvQW*p5%uxGxjK&U((-k+SwV?s>|z#t0@y zX^pmH(OU2%s}a}gI%-Bp1+wWBM@C16JU}qR788;U#ASA5%5jXh`?9{7mNy0%2d3|% zeQ@#3AjG=CTZ-+zY%r-{$5(Wu@Y{K%`*9Fv`lt%L?+M|9J-ibMBGGLRn&y|(=v$LI z_z~r#I3cYA9Q-Hgy>Z<~C{iz^TW1Bg&(gcC0Tn~t;3HR_2Si29n~BD)FsHV~izyx8 zqDa+lts~2w<^2SPJk{%2taW6&v%P-;>}}~3$#bZ^=uD*X-G1<{x-wzE>OC*ComZARw_$lQ2kYw%XdB-WVdWaGjCMJZe! zsxTe_m*F5w+2V=;_Iv$R(QTq*onuZ>FT5MA4!B@#Dkf?jHSQX@#XGNTJ`eBMbmx_= zm-8GQe6c@V8it2`e^3iG?F2LT-Ye@ub2N?BPgr%fe*dA+wVC<>wU;SZyEWeRpbONv z4}MGX9tJDrwTeCd?#l~tBq?kyFj{1Ob@2#SUL8;~YKN)SN%o;!I##XftO>S4jQBz>o#Z?iVl=QfSV-toS9~Yq)AEf0_NOtv#O|7aj>Q`Z z={0%*#8V0`97=hSITA zs1C$3Fqyzt#|UG5XQ6LOWP+yd%VV2VAiERsRx{0^YVk2M9S8io3fc%Sp%@>QORv#6 ziiKjC$go^7&v=NrRDQQ6p6RUR6J^P`=b)~W^>JRVP1~6kx;8~CfI6s#ZPU4_z<&(O z&!P}up;?r|Gk%3{5^VAt5_28)z*Dno;LS?Wmk=&8<>k>dsuyq0qq9@7mIEiL50|J) zs0sGeB!Q=)O7!K?ESe-9%%e3N$^Ub2M?Ouu^R69+_MyE8_ofQVeR1wg$L_lS&boc= zA1?ftLM6Oh7t8zB>e`fozO|Tdc%^r?%Gb2_R+;hi*u!u~1ahGqQ1>lKTl9)1bghyL z=5WmLCiPY_1FJkK>K|MznWit_t_`p(P8?*O z-q6{7+1OOaD?@6{;|-wnjBR*Dm0QFshpGBQsq!miqnFk)qO!vy(PmW2so;r$C(fmT zC$?Gdi3i9v>pIQ+a-X{6+IPRZLW-Up46C}iLKh?IJ-W^kNWAvlZb)*D{QPxj)Uv!G z4d`fNZDT+&EmjbhjiE(q@ZwEO6v`dq)-g1*r2DeTfOMzkW4(}4lfWhkDtCI#2HM5P zw3Pu3pK(n4BaS--yfvdv;~pk$zhLj=$+ zT)Bva^;3ddJUhlwvaLk+iA3sF`?Ot{YH^4|g>+FKEN9M8V-4z?)HP!qK2x^1eQ zSruwgzs+N7+v{UJ$}VgL#-BCUBmjL^2e;QIx*K5Z6Ki7O7Spo1K2kqIrq_;;sd2)u zVdJ*I=7yU#GF5a*P4FfyPIpXqPmeIwQ`TExkF5aT(bFc27+*s3Dr0fU!{CGq&UDX| z3&zO>tK3zi+}K(n3l>(v>YD?C1q{xb5^CmuT-xTgMU@64*}s*ZCCu{GLFv4@?&>Xr z24Aw*$0d49_2NHDD4#u@e-m6+D|<-pREhcL%2|0QYsss|K55HQJa~!oOX&=y4s^)g zSz<>iec24t2+pBuUs_F~W3DiFlnogk@+WuI1@t(9%f?b8eL;L|ES=^|1c_t?Slih) z1@Im85XRNPm>2NRODl$c_^$F_xI+40?Y_JM&9@KW%&C+d+cV)68t_6m^#J(i{fL|xh zg;nNEl1Cn9qTj+Vm&bnaTTsyAhVRI9XUhEJ)>^0)%?GF_qG9nECB}KRD0D!46R>}X zM?o3I=K9*Xc3}TkdHTlx+mzsTgi}@gZ}9~}fjow}KaQ_=6bgkh z8_SMLz(Fq(isX*rIDWxRJN2d1(mLVWM2AT*$rUBmCE1~Smc)9Gf0`FG0nKB?zm(D2 zSrE^}s&bl~Q6iMcU5Tz4U#?Ur6<0!r;<3V5xoJgrV%-A-E1T(o4;{#NFIQxDSI3;j zk06vBoGHFuPE&O=WewMtQc~+{;$S&7Ia^5I<-N&#Hvh9aomth!fsb4funRcF_uwfW zZwewkyTC+b_JqC9tOu=pjBJZnw-)VHd&tne_Eec)RDg4+N?uH;H#K|1I$&gHcg_Ka z(1hy1bJZ~pdJ}32^haC;jU!Iiqj=DQxhCv&?GI9c8qa&6LP32gp7VjvUC81!f{#P$ z0cmUo>^Vo_ICNg^z>5nFf%SNaL9cb|+E;?o=ayahI!@e;P%;Y_Mgn$ z3?0!ZJ3v>ihYtZbEn%Gz$R4nW^zs#+Y)5=YynM)90&G9qkT<>3?OatU6*Ne?raJ8ePb1I?{x@*j!a{F(q4-BUBxjtPN z0r8+4)*=HseDGowa=XkvTA%>6gT7bQSeirNJUs!FTI;}einrRkT%?!;J6*T|{-)Q>Px8hI8_QGq zv9HDodU^k1L#`S+%||A6xp-sF7~^!FvrY1B=6?l#F>0H(wUS?JoU}vZ{#8iNq}tXS z_3lYtod}vd-5-syK2lI48H{nZe++hxSg><^DkYUaFaYu? z?6VY#!e-RZz@ZE@Zau6!9$?at61J;3aLURACU5WmP}(wd?YlkSqu1&^gL&Sw5JyW$ zaEHqXM$3IbyD?p)I0HrorcKic7TLCVXD7a=vJKxd{BGC2v%wo>?9Hkbs;$BG>+-xF z|2|&H$N8YLTx|(do0~Qe*EOj#K?C***@%O28X5oSIv(dash%gZU<*G^UWL>I)+q|# z?4d_5G{&<~Hj{VaB0erzXaG9~RfiPs`GX-y5o5b~hx+V{#j;$l9?H%>=_q9ukq4xR@r8PtCl5(gGo)*HB zYUr2n^dvl~hqk~|y%QcaL(jrvGdyXBo`I*k;Ym026g)YGaw^&-Js57bT)kbB+4OzJ#{E}q`|>wdwonh3g+QGca+R{1xk7qt8c$o3eWX1ROef9#neH^XBWK|mN6{L5 z-j(G`a(ZLnbh5sxt`7SJy^HiK@%r9ji*zHVJ={F*9k^k4UtVLuri^?NY~d6=HGP?0 zDkOT6eKB%V*vxH%S>Dvnn6B!;x~lS8Y~v)*8@2+9P}r26#qMHxR|XxY!Q@TpjA@Ur zDT0jKG2;+gYrwt)8B5$Ha=z}%PxdFmA##hs3MQkhTC}iXPHV8p8q;na;Rxi1-MiFX zD(8=BkLyB zWJ18pT$q0s7(BwiaQ;J4IHtS8PH*rOPDiiF@Q;!Pygl|5MA#sVR%il4^=JlgW+FvV zcnjd~!u64>VDui%-vw6q@GsoJo+unUU;^uTbozuSd>ph-4xw3H{)HRq$vU)j{zJSUXKtOekX$CJTqm`5rj}-KFlLFP!xeg|j1iy{9!l^5DkujBV|>#Y5qJe5q<;g1gKxSB zW)Sna5JJ8W5LOa$8sQZ1YeiTNs{$dEQ)hl|0$)Z54G$oM2A7!tLW2)P;HC&P0{Ia* z!Aw%*h#43GJzNM7dk7y_;Hk(gHOn5>)FRHEO$(V;vwZza2v!?3~N!QJ+de|z=!AE$NYZ`xl?Prhvb zt3NgJ{Gzyd4lN$%vw!5L`Oiyn*1y4>f^I3!ln578ig;gotal2}z;oF55ifkTiC@m4 zRqCVQf@rkGwu(iy)Jz`}>uSLWwY2_^{`vKPfDdYsxXQs)U&f}s>cbzS#}{1mStEW@ zOD7e;t@s+-c&IyC~NGRvk4LEPp)})KeLos=%@K#2i7pEU8sdTKXg|McMB5p%tNUk-x! z8j2&?E}B~bdQ~xYE*zT+A(wQW7%(jzC`u0$*#u9SeFxl zu{*enZ4bnRvSYdPhv51<5!rT-16}BegVHYcO2MB#81FkQWgECs-;sE4eBHw!p)HWi zmIN;?Ng5y}dbj}san;0~K4z-j?~+4EcMqN$Ol zD@%Z~`tBF4jnt$pm8bZTja!aMJ&zufwoDKU zn&^QWas_^1uxx~p#|r*XSwD!MRSEyXo0=Zh<0y{$L!1C}hi@&P=FIK+R85LoLE2%+5l$Vq_3;#VK> zE0Mk8Q;TSha~W)a82ti5h?X}**sJuoAwqRVgut=JN8t2Gd_x3pMwkcJW+QNG1Rg_} z58Fxv|2hKy5rMJboT42AcWBb_p#U~SgwWs&g!$L6IWWztFjwstL$`w4O1oIK7`|=; zOf~#isAz`*Ny5=j^5`zHZ82o|N(?;$elCl}uK-ix6|ELVv`pvB@FA$OB|m1N+{DQf zszv{NE&Mfa|glS9f#3Sp5YUU#U zWK3v+w&)1UtJ+LFT6V-kx6{QY3(sD%CmVh6^<)s$8SuDB@uteB&4fCR_f(4$mV#%Y zo8JLWf=g-TEuUtcRNo{s8ikL$_|m=T1hQkDT2>u)uY*tV0sh^3l?*SeCu2!4xIXME z^0)QmCKCMXdZmvI?a=q+9s2%)bReXUBj-OBm)}9}Fh6ic<(UJg!sctZM6JOo>xz8W z%x@3BOI>-|DqWSqBM#jGnuXdkL#1`1ZW&MnH}!2}nvlqIaP%tb{n(f&u>1zNt59cq zUV6+x3*rRbwhtvsPxs}=KQ;mp7Jl5r5S*W95IaT<9(j$cDyZT*0o&l z$DrRt&#yvBN*K;D**0!i!-|GGsj+V3P(mj)@2vjM<>DZ1$*gbwW1ZZ^->g^yH%YNS z_`-LJkK9RT+ZjGao@>0UIvzZiQ#vyo@gAKOj%A_87+pCh(Og}Pe66Kd z;W>^tXb3p3y3-(+7ddciaAxy2Mk=lH&|8Xo+5Ov6vV z&TY8w>m<1Dsuf7^mI(FCTNkFDx$BU6YS)FShhK-(Q?pL#>nYe#(f9qOOIpvPWOpXM z(6#a8eEzy3C+ymI4Gb&uMa>a5bn>f8nm9U^C8Y>{5r$Xj)s`8 zFulHadxJXi)YZU7p2UV9hDv=a4*oOq$QbpTq!-NL|ZM;emC&wStaUYJlDN?-S3jpyer_W*wLMUp=YLmFXFFSpK;5!E|xz z-83`N3fkcC8~Xi0AAU@kbXxa)3eu7XLY zs9Bn$fv;({bKbCP<-vVn+ErPOs>gfZ&x~)zGAi%5Fhv)g87OVY8Y*na7%CKXKcSVm ze6gHTDqp!6>q~QBcS?MvdzGDVKfdf;wRrbW=p?c0Cv?^I9UU*<4Q*fz@&@d=2R7ip ziG%mR#Z$u@|GI|`b5p8uYlW?`J_5awtrovwfm^OIvUSSWC?Q`Z;&2>VBj!E;jB*C< zq!^7`CuCoP5b#YA*o6?XrEy83ti%O9MC2pC}FwnhRK{i6z%PSE=Lso<)6iC8w8A532QG{^V*%ZOu z2%#SQU>w3;gk}&eBIyGNVXq%TnB{~w!3XF$exe2oWFv$g&PNCh--ZwxZi&RZ5kfw1 zBz{jM{t!aw(0dX1X#}2&z$+2RX~OyB>jdKA2k9G{U_1;Ih)-G}l$RrRJwzA6`787g z7@_Q9^1~nvOc0OW17F5n_%Jmv59-5bEIe#4mCsl``tW6SaEDt0zA{$v?87$%1a$Lf zr&ub5*2Bf(ycTeq55nD1^>$6yM2CuBks(yK@|s}<$vBEqJw!>>{4pumh z53Aws>2JRuk+|=Ti@!-@BvVVmT@cF#r~C` zJ((u{_ewgB=8K7|=t|C-%L?MARdjLI;U7rRivukGd-xha$pce&eTW9&j$--B&+Fp9 zR?*GZ7mwKc2wi;hCKy>%Ai?pQlz?y={)KTAP^0miqS9ehi3Psw3AY(mLw`1l+g8)R z@be)SZFkfH2 z0duSmUk}vF*8}z8>w&Z6>wzATJ_EAg8u5_R)IBvzu2o1|G9>aW1Oc&(^{GY?M++@Ma6I~F&94dA7p)=S?Ul~7YsDw=t&zx_xTE{51Ej^gIL%B!s8zREDMz$&WYvPi}Y0M`1#ZHgOr%-S4SI1 z?pUb=XROUS6aU6r&(L}%`rY1G{Ve_IkIP@(NQcZ+axzj2LJwET-Md_xjx-SsO{a)+C{ z>0KpBu#l{mKA=E2P^Gah4Qo!b~}BK z+uZw7wfOmV$|tEpDs?`%fSm?cH~asq?MtAesIva+RaJL7oleqO2uaA&odgm{fDQ?p z0(Lq{(U1TE(Lq6pBT9?N1VzOe$L@d&3gaZ{z{`drE`tO$Akd&FQ5a+#mqft<1;sVc znej_7I4$@M|KF|Z4vF)9=gc|(^YuB&t+&*z_g=kv%YFC$Zg_cVN1*aKKH+ILFDkD2 zp(H(EcOXz|zOICCdYbJrZaiBl8gM|EwS~{y!mgO{?R|#5GPsEEy}*{3(om~tg={&? zSMn);Vrf~r-V+QUFq5drdZ-D~maic7c;Ep12pkQ_XJ~83ANmtJGvJlY_nq3tOpIOc zJNF_i1VRQBYG2FS!S1`#*U;~M==VPi%EME3vO3gmQOcf+k6hq;cd{wh+_p1j^YNXr zoA>PO2rRf(pBgb*=&g^EPAbkw>fkl6*-^pDsn!H zzh`*CE;io%XjiN%dn>;O#!pQ+UxBHpbfM=~TCCo!#5TvP3pgm3DkiUx^Lgh-T`~B0 z>CkgtNm6QTGv%drASvC4oiv0cVjzmak!X5J6e$s*qef%13w)uV_9*3ituqF23Fe06 zD0Qv27fcgf6(!&CA9k@h@?-R3p^Cl02=2E_7s~I^)$(nxGF!McH39%Z^OOSq<*O_; z>r-s=%#AVX(l(|!rG)gF1VB$(F}lP-%|`TIt?-Q91KzQ(V>dI2BT49G#5^R^2tbnw zQA{$ki9*1!nkXipC%DdsnSZ-)xDUvp17Dh)pRXB1&zG_A!*37-f{-(*Ll{{Gfz|{- z2+Zh!c&#`==|B&8q)oW6_aS|6xy^^pplN0XQUZFYvgwx6XW#+K=O z>xJCP$>@6%)h{<1a9jnI{QLbZ%N(YObJyx|;7or!>os--LtDkpg3u%8b$~A%=B2MQ z?+ArzjWY{%Ndy7aG75t}K@_b~uTpgi)&K%X823kvA`*dv5v1e z$i5p=T>g4nNTr?Na!HBf8h%GRG<{d|$J*KGVXN2ZdcwkVW9ht8=$TioDJjtrZ8ra~ zoede6p{mnR7X&Ow&pXv2cBGy}N29~aev?KTFZP~2YxXHtSEAFG{1#gz7C)ul7|Kot zk)#OJI4G7(3`uuO)5i+sC8I)B8;kEh#8P9%Rg)TQM8Cz|qrB@7%N_k7d=GhS1ajO4 zkmLB;cvbQK{+ZDGw1i@Z)DCI<0Q~Ra*BoX;Mz0u@IJ9=Cst~_yP;6ptqRQwtUVRwN zw3t7QJK2qV&tdi=%jb*#jFo5}Mo^EfPEQ;RhH~1j%wBwon%_BsA19Z=?< zc8vewuPopAM;V9n7O<@0NB_!Nv*G?heX>OZHU8=N;+bCrHq^pGgEDO?_lJj54&L-0 zTc$TiIDNPHjPC<;&|OsDmb{r$ji48$n>GR(Qu42+_jtnen$}Z=uu*{G@=wRnm#XU6 zFtsk(E@)z9pe8Da^e7jrV`@!M-^y&)6Abk&MO)}g{ZUclUE)SjReeV4nay%3jFhrr z4k6z>yT=pdrflO~(nhI2i)ze=IC-P2#;u(F2eQTkV>C}W@<)~TiHiu+R&%GJHgh|% zG(*?ha}VX9RQ)DBbg|S_TQ-&jo-|Z#5k0TGZ%s;p20-mb`-3@d|01xwS}!5lr1%X6 zQoz!%sDC=1(u^D)dVf#L)2Vg()=bA+QkAqcR}(+=ze9R^SNGdhmq1Z7@h!YR8{It{ zZ&gbV*(@IoEcLX{_UrXXKBM%=*Ta%+1e7JfB4o0RS5@hevt9Ncxx(HjR#5p1f+osp z(S;E%yedIciKCG-r)&t|%hgAoiIT>Xv9M6eFMr5}IMINm6qNdbp25CCHA_TX$ovsH zbyW#agjag9P#|-Hrg29$!o(h_m3&bLOVh`zM_1f~Yj@VuJIV#vZ>~*&2a_3Ad>7_Y zxGI@=ISy`XI#c^!{P4|aIp~z2XZAQ} zt1Z~m9+eK*;jk#=)QxoMYIW*3a@38kg$!G!`%O_Z{80vUcAc{a?#o=7Ka`8dM>OJN zpqGe`q1s7lPJfu1Z={P{nb2?)$}zhqYk|t4Pe>f;(j1yxNiFxU$NjRF13X5$!fVHb z_cN%4!Kk^2N?X)tp9}MWaILIHn8wgUP^TJxqLbOO)OM%w!W;>sIda+pfQxFO5iJb! z&gx|FsPT>Z2q(Ah@^x+MYu4qsgc_mY9q=h|Hp_U;c>TpaiRk!W7o!^>oz<|0cBE4m z@WKdUP3#C5bC?0z-d?J86q*TW>O_u;Q0E~;eR{iT&h;u+d`|xA7}Ny&m^R@WrLSF) zT(TF&ZXS9mfD!K{?PT(SPKdO>Q*L>^|}4QT+oevYbH{LaoPeECU0QhGQow zFj=m|>*{oBeDN>h^>unRe%h?9j6NfJnAXtt;ZztJ=uowau#I8r0P4o$Y?MjqF_Vcu z3bST*t}BFiA1qA!7l9pTD0Mo<&fI=iHk3NuFHEFjX=9LQC>1-mf2=_fszQa%?MFqR z*l2vo7+TzYYv^U-meANj?=jL<(&Ho>nM^dYYVW1NAE+O?g+Wv$SRz$FH&N>6t^unH zorN{+cKq2aBPEOBsH!45i_5TIJ=566vZnWJg$k`W5k=I8*Bk2#T@m%X{1aNQA_kU8 zcqLnbbs$dTo=@0_q#9?Ex*YjqkcKH{r55K2QT*U1Y?!GeO@N+tlm(jzEC22jHYW02 z4}*s4bDmYsLtU?P>))8w_$te2D(H zmubtSp!}OnIddG|!<2DJL1%J;<=QS`6GJA0nhARm^9hzPb3(AH8O{AnJhGSAm@{J3 z2H(|{g*3@aj~L$E(-oBwovG!O>dtk&&ay()tvbPyGhb!HgW+OW#gYQyV3Uc3UHkb< zC$Np#$=^T0hKkd=_}LQ!MByr8LFB;0?PzY@033?d0~S!&6bUs0!dNg30vD(BMUcd5 zKZX-)_!@*nHWa3G=YTM!o3Z!Mei~9v)_^e5CE-k@iY3N97np&W`AeU&VWlxxu6ZEy zqa$$#?yg0l-V27WMffHZ;_sl8elzF{JoFT{DHL`gJRA=>#UnpsAG)c^BBZ@kPoe~t zPL#?`R7O^k(Nj4oe1O7OIUWwujv)PxDCAA&i9%*ikmN-72I=7-{e~!j8TyD0C4C`m zJxSy}jVJ_CXFx^o+|SpGLX>u}ZQ$0^s+@Y|>EOY3A;%^Bwnb^$L0cA?*DQ@klE<7tCpQz2+2zE=&3CAV+FWE; zPK@)N2^m8(hh)c%z%U534au8mp|K{(8VmeZ8u-XS?kvCKOSYK#_+P$c&kPW2**Ugm zL-@I`Sh{G|kpH;pD8AN3eCpTC4RG5xzGiZaT}H$!S0f3+5}Je3-io`ffwmBW--eS+={s5me`+zAfjNG)Qj%y=q?ZQNU3Ad>iqP%ljxGU#mMg3*Qcod;VAsnNIrn zyTW5fUpNs1Y=@VG#YrfGF|6AtN!>bw&bz%=mb}VT#n3H@mlA)aY=w!XsW!aEP^+&C z^9m!zKq+Klr!eMMojJ(BLSoxabe#*+WUU9 z(~_CsZ3N2YX90s`#FYdy^>koOHU?xHoF}E2aHX>y=#7hx#FZZT zib3uA`R$tnh4x#4?8mHRG-7M##$J{e-@>B2tIL2?I6Kib8-@VTHfiTGd)X(ZBFvr< zUP4l7W<2jaOEJP!MJft2uVmNI*f z!Jh2mTh6luvQ>#_;y<5fiQ~6GX+7sVZ5d@Y^r|{{=!CagvL0!Z>J!j=od@;3)8yM? z;zpz6-6Nfz=G5^SKd{t7RwKPQN!fSM2IIyWbu}X7eA}5{#+p)G%z8LbQ<>%xFYLZM zS2+@BP-XtCg>U)+?G(j*Kd_~l8OlQC#5m}bSm+JYp9};Uq84Rs7q(x($^IpZQN3u_ z_0PXYS(b0ck8BQ$agb~j)3b*tW|(^Z;y>AM-1YcYX)aS$$Us%JH_!vYctY`}bo!== zo(<9;gH*;OO!4L*O$*YzAhi+2n!k|DH9dloeCOzxjrZ6syEA%{}6H-ac0z$~Py7(|tX;|DHG9_RGA! zm&S?r4k#X2p7af$h~oVZECZ7Vvh*SEbm`x+mF+DOM-AYJru@V=s#IM03yyg3wLH=( z7W(W?@%zCI`iXB$`Jfx7%LyvRHF=;o!OzVWxq*3wjS-4&8(%j^OmVL$-{1BEkbR>S z3w!|A0BLEf>uXo|%h5+HcieKv);qqwBj%;(BR2;u(UHANOrHm2^XCDB<@12a7X9bX z17`T3i$_c%Vp0$z_u6$;g|{m?t~*@YUEMD8_~#v_Ub89sNMGltfsRUfjIP5lM(UX7 zoUBeB1@2TwQ?uZ8NFB3-QHI{ch@{sHz2QQ`#dQ~Qd!i%um3Xq+yCcL0DyLRXDiN&f z0tUMXlbrY(S;et)G{uFB%|#tB;oV}sI_9OM9U|G*!`)}SLE7{y#d0S6<*-d6PT<0} z+Z6(-_}69o>vL6PQ#UqD8Rpj~wH61Cjz-IHJM6FJriI#8YT~y2j^_Q{ap^-p608x5 zn4y88N==4Lc~tztt;%+|Az|U>@#aE6Id`Nx>$}WXi(Y!Lu0^nh)r&0=cnr%hs3X0Q z^N-G8A%ZKGZ>MyMIBK>laX6u*a=|7l=d(^-ivya16m~Q^wzIkjMX0w2l``~YLJst& zEs4s_eC}LvsJlkBf_zn-rc;!UQy**l%rFE1qNok@7=0Up_qd`EAw~a9oCrPrNy{<;jXw6@`^E|l$^W%h<1Wc^AhXodAp1ya)9Nw zINtstEaS&c?wTi>r1}$S{Qi03Ld&|&@UjoP!Z9^V%3r(8O`Y@GyF@5X#@7hBuXjA# z#rx)of6OaXW8ywYPgA&X*B@^#pH-F_?@utK_ z0L}0P%rB4G!e?goc`&as31_?>o;6<##7)JmLe2}F5^l?ZBE#i>_VKaTi9^`mcdWW08^jwU zst(AgP1S+R|2)Sx-XJcPx2J6>;ei`O3;UBV=|<7iKZ-BqH4DWBZbIfKg_k_cI!my3 z)P9V%d%~&#;j0k77vYux`2|dK+E2?*wi}^vB`#tRo-!c+6ii9lPs?AfBfBp3rxkzz z{6b+Wz~KR5Dj=ygYd?)a&VVqbPZNdQ6p88 z9}oC|!ntTwqPVe#DB@M^L)0_{y_4c?L??kEQKYXXiu;g& z6Lq7+q5&5usWC{Yn~PTqf`uq<$O_Uil#U0e+J<0oJB4xoLqu`^qd`jDobD$rL%P2` zNc$)q_o-Ti;1h)|9QcbJDC13C_P|ZkZvG~8lRQAKm z$X0Rd?ND`7iRJ-f6<>)M@tcT#Ut=tev>~&_auYYtma}=xQrzL;lZmwRTb7EWt}Lx+ z`BN}Xb-?9zY9Hz#1&E$K=@&geN1Ak(Onrjs@m=ha@UIM+T{87%ndI)Yk~#h;MR!S< zUYCRgg;d-NVc&>(i9~CXio3&D&l|$Qx?O8`iI=1wdUgw0-z3iQn~T{c@d9Gb1J6$> z?G&qB9Zp5 zd$3RTI-yzNxkX*K;7U-GpJYrkf6m z1#2-;0qo1>{?D`ipX7A^MpO1i&zp*JPwIMM>nH!L=cK8p)9tWS{ zcCp8;XN5CxwE%eh^9*ti3-fg!ry3VN+{0uiVh87R|L0l%Pjb5d5}dT-6dVGuBpKR^9}JCIPWPu*p3D3p>6>{;qrNHJ||?(!>2!_NWu}bu1Kt#Bok$Dnt zDBABZ9Bgw8`zTX>_0q+Q#XoMlRk~#C9W_(x-Ct}hi8UE7i5H~{e~(KpxR(E6Iac(| zrRI)>z$jY~kmq0tZESH&I+&uocENMaWoW@9Ipfs5lMbueJdc!11BvzIX;fb{0rJxk z-5Axd9?lqcU7J{7hFz<%CA?uqK(d&dS-z#D(Gd;No4fD8OHs|wc6;MungmN+rN&Xn zIMZcrzA&uot=qmBVKwy%<~=fvJeAZKVQ^ENII#BnKtWqoDU^s+lN8WE&_g%bGs zN?vo9SQ?RO-kqWd7k15yAIHz!C0g=~>h0#;Zw2zKDK27qIB?jS485Am`ELgd#$m3T z0&>|QKwU#cEN6wdS1u6rMsM|~5vt(Q?ZlL?{WPP-iUDC-6FoQ}Oar}VK$y~>7!aoP zx&dKI-!~vk=?4ackzTA?J|G@HtpKM6XAsJ`0uBh%19s?1NHxytz%?z{=m4e^ ze`A8-;h^{8?-XBIB@SbA`5&spv2&~Olqta+e*%32VM{RlCg^E|6N2GmpcfDx6%2n5 zYDFoqLQ|h8V)-}M7r9crhRxl9I64d38>F!^!b7kw3DO1NLt-pyRuM&|+7Z1Ol*}pA zl@{olV7P^Ez8f2vHobNp^cp0!DM7d27#_Z`h(e;#)0&h^{!@P56S=!r+5=&<8 zFW3o3mZNV-8?_(8irheFqEaU?7f{H; zc*XG1&4JutcAkf0NM5q6&w7v+D&1q!s1tBS87~u&J9J4E}@69YX_bmL>VfuHBA2JepaA z(cgZmrUoE=MUL+~v4phHGIEeIAr$%TeE#pmN$z#%+B95XBq)3sG#~5i5s0I3H^Mhy{}vitk`ccV;p>C>XCV9!Nth=n z!HC-sF&?8s=!VA-UO6C4o6MIGo*B%40O6koq<=>DV>J0S?_Dd#`&K?E-XpRGNW$Yb zJtCRedys)+#s4y{c)lBB$9p6LAIhuTqM7NubEjvEo5Hz$x;%nS;+@E#iopLB94f~B zuR{fib&EXWV*L{ixPZKdzu*z4L`h1|?l}gb`!T)HU9ICi9qeNS%UaZtP!7;2kk%ParqMp z$@&WZ5kK!rG>bcgOj=Yx{n1krkf-wR9}|nL!qw^TT-b0wWI&dm5}#NQIRj(X*tL!y zJ0mcuejJeVdBr+$O4tp6wM4`&4ku1&MhxS!RqYQF$wH zI6ubqR=}Pg2b|TzEY7tP6D>0x3fN-eTt2|4+G2pvcxJ!jzdD5sxK^@44+y#?m-A@? zrt9DI!~u0nP_NC(p@6BHVh;r-SzmSG$|7|a$4JBEW7HfugM$f zrG1dui``KNkkBTiHpNv6xz}|%gG(Q{og1~NqqOV^*D%y&QVi;o-{e@_DU7_S(_Itz z3}DV*1Ohc*1mtRYI4W*jpqdDM4b!nX9RzG?$erUaX1905Lhf6bYEgtb4RzCAI=^Gz z{$qf|W5Cvn%MknABH4Rq_PC1)DDTrw{e`zHZ5f)uQEHP7M%@B5SdRhKbLTOs1|7tG zS!&RhQ>dL_?h~qhKpjl_q_SZ%NphPA&7qdA;XTp1cGO^zs10fr|tyq_IRytWa?;T^1W*R7Fi?44*Jyilp4|DK6Doj(N`oWDapGp{cv8o z6kD5|+RzkdbHjRJ2R51a)+3>gFyPWF$T6NY7%2xEFX za#oB}blv1gW{HhnQ0@xBl2$V2_P`su-X&6EiDo02v!eShOG$$xyX1v#S)X(JhiPfg3MkD387h{%&JsYW01lMd_9d~)RhyjP!W9(wusTX!Chh7Gh)l=Js!zL zr}i&<+Rq>Ih`GWK?H(GN$Wm&Flg7IQ^-TysmDtNyZWZ&#Kvz5yZtf{G+X6t2>)zZe7xe2w}umOEC5#bCUB= z;NjbIG5Q`|O8*m81ERow8on_g8LsP^(|5PJs=L+IZeh9dL3nAJFcM>S&V!UcZ#nf4 zi)%-hK^^i9P70THg{jm=hPTy0O-F%Wd{(?1+Ab~Kbb-bDRzEME6_fVi(gI|y|Zqh^*hiPgncA$~UoiiGhJIiX@^oqgd4Mc4@^*b+MeohBmZ9^4J zS&B5ONTcA_s(z6{^=T2ODXk;+=0UL`9nu>H#cI0g7mr^D82BgR2n*E!UE!>2i`{)f z96f}fQRDg*NRi>ptBf=#kxf-0e0;W6l#seQaJKFH7EhihNML?8= zA3!*!0UDA)wP3w^wN1&*CB;e+ai$v6LEt2{5oRXkC13FWx{TE!+_j#DH~3NNS<}BR z$EaKT{<}OHXD#=UuKrI@gydt5#p<@>pJz>$HDZ4;h7X!#;}xSTN@+}~bwFF=k!nT_hdU4Xsk$UEw#T!kLmQifb%`UDp_}p2+FyoZ)@&>aS%EzuFG__s9jQ*kMVFfHVsWWMn*?iI zNg`e({6uY}G88C=ZDB7CC96L^^cC@beFcvFpoUWaiuh#cYgI>Ca;{u7a7s?Wdwvh! zs`g_-IxbFO8V!Xh{mg(crI+(B+r$Daqi;DilyAAf;O}~;IEA-o$!2fc-{sNogI_%U zXzgDc`ULGv)SLGv*7XK&}qY+WTp462wyj|CU;nVrBgbO9`1 z{^X5$GLC!pit)OF{KEVKZ}qK1eILx0Pl&v|T8g_eCt)8V+6ukU!?>wUdv*WE0*eD{ zq^ACE#yxAL)sdmSB#vo>$GPrdsf%^M0k^gRlX=V|kk!cKdz)9#mQ3ciP|Q@-kn#?` z69KV`@s63;gPA#dRQlyXOM!OK@-WHI1_)$A4%YO_OBe3_{g_&NhF~pGXMH#xk&+Z4 zOBi0V&7Ki?VbyBax!t8>ReYY3){h}oegB*#Q&F!{6(>yk>6Z;`dk)h6zGW3Th1LQ4O8S=gV$L1{<(O><&=`U*rn%Q zW0RG6+ah>!{b_J@r*2$+ZXej?;nvut@1IL7O{o#GMQ<%+)4~><`J6G=#dza3LS&nH z`dk8XB`|vMX)p!j%-BuI^{E@>rWn_?t|uVUU2Bt-CnMmI21fec*_$I47;m?mT4wvJ zr_D6l{cly2`m0M7`;&g14n|>u!|gwG^RHc5E(;(jtoBm@+5U(>N|)uAqT=jFVRi=7 z?~2(_)Uf-R?gW|*aTSQO;W{%uvACP*el=rqNheaw-LkQ$TNg2=F{R2p0K>OiUw*Ce8y4`&-ucSAF9fO;?GNCTT zYt9q_HW+zf+e3-o)cS-o^m(kt-|2Iv%s-sX1dU?U3rL8M`_LHQ~n z3uq-4VKc5Y6!{OWwELw>r@a@CE55~PchuZqNHo5G&eU4uKY}#&F1r+1O&(8^^ zQZYR~D{)qlMM1Z09jUB4YZ6kPqArR~C!^Ep&~|u@g7HUmMJl8j2eLXUvRgz@`rw=e zZ`72TvdPeBe9Gu5gMnr2?^+CHe#u4*J71iEH;B3f(hDj-9f^IcP2hz;)u zxBH7LANOPWL1$#)C4R?}k@j$OL}T%^x(8f$Qx$|FID41uM*DidEXNg7aZp+NHC{J5 zkJ`JbH&XwmkBrWNsFQ^{o|uFWOQHhG&514OR;>}utZ;;qh#^E@ig2lMGrBK(5gjlJ zqe8OUHPO9F-&4D10{V!F#X}7H4&n?g6=Tpz(SHOMxiu zOZkKJ(crD(f*L74mKGq|kEyyinl(T&Z>W)+YzhCeMtXK6)-UQJheRW^$f0{kp~DoU zvoZ10qGthrsaE3R67A4KCt%*Q@s%%1S=zBj108#$^U4J*oPUXP5HT@aJpkbyDPj!I z_aX)^4F44-X7g$UboE9-xKp)*Nt#rc|G%AmkU+E7D_vVGE4mp5n^tWJmhI2pW`2VS z=he!szP>QlzO!e~u(C()dZul&L)Ve)w8GSdHl0<|58Y)_c3t}6$CLcAdg(VZgzzi) z#d>ME{SM`+VS9IJs)BnQ!%k!<&$xul@YfsxLpm$?Y?nDVs$*V2PCpSA{#s1sh2yLM zArr;J(_@OclE1J~x`IYZ2q8x|NxvH`59O83()EcX3DBe<#mh#yNCUJQRty`={DWpG zW&XbI>gfOKjDkmVsn>2ygm8x5as_bfB2^HLsOD|Jqqr8Bv%_3bFc8RtQ=#G>Pcg~~ zM=)ZqB_gvYOp2>q0CRz;#xl&iayy^aBBjJVTPk%d2qNN{nwt=+;CHo1!(uH;vLZC! z0C+|)X+H_?JG`ky%CR>p35p3O7F2-g%Q9UDg{K`JDyl_ya->sIw`)1rd+qOD6a8c7 zOvTioAt9NXO-%$w!^O?guj6x6?sLJN!6|0A?F8{(y;&*&R?3?2#?sPd{P1Qe2MURR zeeKyStiqIeypu{8t^eCbqq48_@cObwGj6XHwT&70; z^Hb7q``3QHEl*3$A?e5jP0{&==cVF!kMeL^loFX0r%FPGVl0vBdE4{Sp3tpJeH|}I zVWHQDTS<`9w_Pfc!!w_6<5OCttJvrK{#GfSea3mKlsQDREb{bQ7O8L*{KHmh$T+h2 zsVmcAJ4wa|LweIB=RsZXRB2(1>ZGHIUHv-FrRD`PE8EY1P<@l4-_8?uNEP6`bcdAg z4sq5s-!a4D8YU$bYg_-&t{fYCc-OuaY0YvdE#z-SO>5LO!Cj$$O);G2_Q=4xR6z~nw1ioin@eG9YRx-3KCU%etd7kaxRd~Iz~?tr(8k;V7ZZmD*V z4A9rNSGp7u6=}W47x|hrk;xLI=G^%@l%Xe4uM`pTzb*{`RBG=7pwgKGzwANM_{lcf z2eC!I{I{g_Om0Fy^tHb&{hFEL%fc-3`Be_;B7DqYX|}sYS-kAAwgWJTOjD|XP?w<; zDQ5VP)Tw)How8u3++D)Vs*Q+F{hy#}#2yM7JzB5PbvufkB$nPE5$5I7H1k zZ+0#WWLp*@wMZ%UzkN>`t}0Ma%Hzc1QnP3>f`{knl43L{wQb4G z!&*KLY^aiI-ULW*Evm|w{aMOM`ALXWGFQvpdUafj=++B&r)5^jHP0@R8~DqAmKHJ2 zBaTSJSS`;!BF%8S)rx)4l?*c@S3xpF66D1U+U3?8Ve~6n==y&0-Kq+E114XvM{TeH0^owJJLvZZrQLP z%8jYkq(U9!sPHbs%aX~*wUp!{m;=JONrvB=b>`Po-iDE6>db{K79!w!+pzxoqiUm6 z$eSef{vrMG(Y4Vk-}sr~4U=(N+*@_>_{`ioSqpNw|{OtdlYN?9Z3DmRwMb!Iewn7XSD@77Ct zpd`rFg?Nt(OAOuu2(9?)cO|s!u(>6=27dTm$)=mDEG$XnKfNnW*N;>PAc!k}m2$Gq zFM#`AkJu|X&R4(-ANEr>svWBs?}?Ds4Gp;puluX?N@$Q-%6Ggc&A(-!8aY-us?wg!jwLLK$s32>aqILeoUbBmH}Z(ui>}6FMZ6;^6?*Fu1kfGW)eUCfpj&y zj>mi`jb)pCMITDpvik$9;7Htbo@f^QHV_?-6&~)OFqKmr0WEE!5NA!Hcu0|E5``3L z9#IR*Lo^5CDxz69WhXikQahrfux}u0g@rfK3=|NDR>BnC2}Ds4I%1>yRSoH(ZYUU2 z1RivEkgA%}2tOGN8_@FfU^7uXK!r31r8h(^GleKx#!eLSw`G(M8c3^xbPZAPBTZ?d zgl0sPG^LGhTpXbbs9K*QiU-BwRT8xmMf&U@T@<9MCN$!or0{61E6{`YQW#CF;;f@gE?)r|qdiQjZzEU_oQLQOU96t9e1p-Dpgkz{ zi$LC2CW+EYkf+ck!n|ofI-!){E~#EpWAC56LB>%@B_VE<^vLr|dOR}a$Sy8)$@Q|D zhrmC^y26I2H|pwjYUHx=rwC5T&J#~cg~mldeiEl3qn%%WQmO+!@^4N-E#&%Ba7bYO zR5E1bl~W=;1>D1?xT4{_iAt4S4j2ydMPLyTA{8DrLA6M|uQG3Y?ikzxdmLHG*I~V9KSqm7(A6%dBRaNfiW_V z_A`>>%B_88q#O0M(QIURop1h^(tFGlqaxCU_vVQ3sgd_J7VzP{yG3>VyXtG{licKt zBKSfgKd*#F2DC1to^7}F=5-)lhPt` zTTBko3|;^|F>S*`SPkS7l(ra15Bh&4tOi;IUajIU(0y8NLTfmQ_z7jNk-JKpS;?1> zY6tWZp_$zpQI}Xu#^-S^6~Tc|{Z_JNHmOCjJDVmcD4I=&Mm%Q!*bch{3EJwi)LkO; zns22wqp2LI?3OF#AV;QD4#d`6iB-L7^J~6CXQf-}Lxl_$J{wL;Pw?MRGSxr4nHuoQ z-Q*$u6n~nMiM9I|cf$c`^Jo0S5c7L~kv!Tv8q6<;nBVz}-s5NOS3>@He}pM<<6~;j4_& za4cSA@KS0~Up*AQ2JR!TGz1}ioZ`PfD-DgJhDg9Wji^&Q+t#yE)y<*J>%X&n4=gQ! zLJmFj3QKsdRV$zYTwaMMN4CT-^~y7<&Pj<;5l!?whuOxD*5qp1rQOq{48#TfX#KTE%g zjc9=#Pu`}3Q)dX-a|2mbMQQx2pQSpJ8Ef0N{Fvsq1H1FN=f9;XvT2*(^|k-E^jl^i zd|bN{-^v}ArBMsww_#_N|NAC#5AcvGdLfg~uRG;!c6B@Rd*ICqUb&TdA8HZfMR@ zpSfOr=7xT5Cpy=w&w2vSVcreRSK(=!7*wKV#oNY{nS8XrX$S#*KCcvIi@O9Tvf3|b zsW~7F8K-b`K-h%vzyoMXKl6+9Zw7=Zy+Xu4^{4SCgT_!8>Ax1rY3@~j!3+b!#Gq|J zm^ zh+_SFIG8~-!bHYTg5mFpLSp@MFdUEOqxEnOQ7lWR5yk5BNun^|YaxpJUkK8liQ+lr z9f}H0TOgywDF_zz0-DA_s=ACAj|C=$@xc3t;z3PBC!&T#@t`9_@!(@bE!y&S^rXe& z--D;_OZZ#iayGN5;1?DGzsS~Eu$@U%{UA-^w_L(nH$}^% z^wBR$-A_hwTeMtdux(rDTGc4!@@>)bLwQ#9vF2@I<32KIvXkyk2(7khav*XtHm^Bf zS?Drv!yWU?^0EHU)mITCzaAD;8VC+$g#`ubP$pJJ^J%SO0$-jar$u2ngG%d1feknV z(s_A9lAHpm4XL@vy#^7kq<@+NonU(UvA~9y1&|2f?74=2k|f(@cp59<$;onMykW$~ zfY`P%AbB>zH}=MWZi{Xce==FN=Y&~9yod)xYF7EeyMVC?a?B?`*y#mglkdl5*(|#G ztdy2HJ;o@o+w%SDu@8V1Sn9zt3@T44XBO?O*g0dTW9QX7j|FPxve983>w~JiPlT+Q zy!7^@TCpbVMHCtS+4QQwg4Gyyu5tdo3vu~_3k5IQ7lQ?J2TPU+ z&qmNZ8|UTPIya>4hMAUjZfETN^+g00G{p9-SWDw^A$>QjrOjc*BT=hLh{cV9 z#v_Dx1|Gs#tfbf32`*@ke_f1$*4nr~gnjl-V4(-6p^rPp0LRllkMd37`IjkjCSR8>TjoW&_rO-rrMn_!Q{19}mZ&17FlF^8;Uj~oX@n%6%~5uuXdt)N-t_UYgB+)LEnhwLHfTH z05&%NUI4#UzDkAwy@2Or$Tgv7y_q4e>mL<(Ri<3;_!&c^_G1D>CqlgbN*DqJ;b)3e ze_Fa3a*$A%(yPKXkff?Cd0*;-m?T28;1DqS8M6?DlR#s9rNd=_qV>^)fTK`V(+a9w z>O6p%Esw@?P&-k?&kxdNK}z#9#T!U81xlzzr1GV@41!>SDk4H|LLw^>vN#2lo}-$S zA-^h#iifPMg%WVX4x)JA5u(U&Do9l$e#BFAsPRPUK|~>vq86bC8PF2+pb4P#AXTyi zKB{C1I%iK%Jf71;6#P_=K0|XfBYR?8K@uM@{xwlBt^y^-Bsmh3RUmq}<%7eXIPaE8 zW?cy+k{tx>B<>5p;yyKa%`2aiVsIebqsR$fLPhLVPl9#vSi)#1Pb5$3@xIlODaM<; OQBNlL@-HJSGW`Ku{(RnvjHqmx`bg5Oq|PfUJVA8D1I? zF_{kO$qWH>Sp{*|gs=-JNJLigxrv~HibU6S*vanQ8Az}RUih8UGm)@&?|1*-f4;AB z`c$2IcGam<=bY+X+#kN@L}X) zj4=MskWUEt-@;@yA^#~%?O8b(}ev`;f#T>{~j)Jg#867{r?y^oss++ z#tcXP{n;oH?&i?BhwF+G?Qc`1t)zORtWjgshykSMYT$1l@lk4jf+{MU^Ok^ zZn2RpVTZ{l`v1ht@9a(gkQt&8x-Ic^l3+cW%k*o6{>(SxVrRT39ht}GhIOlQBfIZ? zNMmFCDn|Izh;sXx4)!5c-k3AzFR=dDL@sgk=+TL>Rn(SfJ1*75B-%;ZjNCuORi)wINz-h_*aLTM?qImT8%a`sw5tfgdFS(k0iKgLT^dQSn@S zc6N4rR8^AglvJ0=)SZ%+W|qQVTjo0WyKLNhbvLTh$W&IDs$8b3kg2LeR5w@D-Ld{5 zn#Xk~oMQ6gyCb0ykyZ3T>>9!5K6qRz;IO^$pvLw-_@1O6);DEkr0rd)XmYfTn%|RF z%PHiTuq4}>P$)+ka!ma7pFg9z0^RNGW?K<_GJUps~ z3I(=WKUE)>3=Nni`I?G91er!u5GdJ@(-|`|jpCck71JJION1S{<#rgV(2tUEcv26; z69BIphGV*I7>?18C7fmrz$Y`~~tI2K@HL&?xmEMVL) z9MkJK!QiM7F6NCJy$aAMAiEdfgHR9bsWM&kisU17X zBnKOdFbCRzZ~;JVIw8*@G!xQ*FoO^`!Zbp5Axt6UG(y;ke?kZ%#6^TamkDiUMnHK8 zp}bKD;|Q^Y;2Qv;`~~Dod@vK@LzqEGe+XVf2o-T0K&Z%q5Gtrd2o){`h!xlnLIukZ zLIw39xLVjb#>1@Qgt~cVx?5N@Hk;YQ35`Wr09xkLRN=F+YK-}1UKaBe=d@%o28Cdm zlts4-wU%sJE<6E$4+uLgxx<$I1!e9MVxk$sJNb25I%4AzJ#Vl?@|`&aIg~BrBZawz z=VX2%8kRFzoqrgYq4+g-duF`wuSrdu=kBEs3L7TZC^zx0^jKavGx^EPlK}(CDKF(U zdvQvSerUjw$!hFec-)E)n`} zIi^*(o28AG=z3xj4&0hm{ziKPKW_Vkwl?WxeVf!<#|X_lR|pNUbuh8ck;jsz3FD5 zzEUe%)iky9r^@HqVQq|OipC3p?vVoDYq0Bxnyl^|{da#E$2%Tg-<}5J8pc}=cMdof zsZXt}VB3#g@UN#iOb^6Nz5My36+u~Y{i}De3{8Bu_XibZq-XD`7OHD!KhQ-zM*<{bUQePe9eCxD zXn?>(_W)cB@C|_913VPX1uPmaU|>!R+_PHU$B;P^_pbz7(MA$-0Xa_;A^$)a4GSNkiVz7V*?GoIIbqSf z48>_!&hy2lVj%BP zp`$Wd`1-bJW$-K{e*Xj;FKBPS#!-`^RnXs&$`KRi5ysrHOP|I^@-#!qo6O2R!q<2F zL7q^Zz4P3(H3!0BD&dFwyPlhtM$6F8vEw<($wtsklezj%B`(-lP* z)3=58NW?)}$;fBASIk&Z({zO~v|M4^$&Omz+L}$Y#;3PWuJO_E8o#=x(r;a$=~E`u z_;eF0eN>yz!wwzJ!(XCr;EzkE>(XsBa6tEsL`+Jj(*3#W$`>TZ+P%Q`f%SFk$F7L z4TZWuJJs4$P8C!#_{GPPV;9B;W7STz99uOF;vJFQW?Ki$cdXoOyAw+?m~E{gcvgm= zdE0sF$vaF;(a0lSQt|hDiHGiBTG=*wdmkHFz>^I99=#AIgbNXZL5LJ^`IFIweAMg4 zV}^`VM(DYjm5igH|4g(^BWOI|K*QdZPCNAbqV~*{xFoY}eJNHRKjY_~_^L2r#)Bi` z!>ax)If!tDHJEI?k73LF>asE)6*fM&v0!fX*AlUy9F?4-HgV}#YMEc>@Eg6vwBC#5uzRUo z(nrYicC3C>9tp8=9h1d?PzwA`cy&z?aHjKX-kba+2wU1PLRvzwD+K=$f+%omL9mNK z7y+^pLZBZPA3RKDKDdWP zKBz$6N`#%aWhnjua@i`G7hZh&W?pE1<~gnO)RCt&T#1iaBJ6)=R?eE$#j6Kbzq9(* z3XEj$jfPpK%vfJ~u;-~YlhzEbd1p-$2lMV;A@|wJ7%pIBi_2^M>hMGmEK~ubo|uJ( zXUD{^d9wJ)!6y$rNe8uoU@6J&G9M8>efIdUc{XU*-Nas*f^qW6il~KI8{+gE+qr$p z%rc3a8N&-JH!K?k5pO6*luL%YUnt$dr}9O|w(=9IBKY+nQ`Guu41&Zs&aDfb>h6}fs`}|3GW0aNgO-yFv3o5Or{3IQIlz>|VKDdk7jJY*99+Q0 z2ooAi`S^N*KT2S4BddqupmZa{MSe^lC%iO1NqD8<5JRYN*QUhTYaqiBNI>EKU4Y}^ zJtl_mUVyU!2kBW({};gD06s2+vygW$;2<5#=}Cb9x$}cfPf`0Gh{8?yeT1+He;$IR zK%$KyWL5~?jxd&x`$G`>!^8*AJ`9{e+A$u=`4(YlGe?*R)nYj&gpeQmiTNxD6G#N9 z!vx4^lL>_0CtIjr-tf;T;iMFt?U}4R+cVjr+0He3t`f#h0>NH| zvpsANEEIy}0WgS>kFZJ19)(!9n2i&Dc=4u5&rTdaUdX?DWX0|zpe00sLk0_w=!u5- z4-j+sOr~fCiRNQ?>*Zgb7z4bR4N&$^$C_u0vzHoE^Oyj~TCX(IzTmr=&M5(SbBtaf}VzN@qmUNinCRZLGk` z8$gClYkW`o(Ubuv^>0le$+;ICjtpGSXHH?6K5s>`l`7hU6O!gv&|Lu&h3&MA>7_*t zv893T=+au>TvqBHA_6A$g?@K?D?<5#p>03}srHwTn`>>30B_E^yG}>S# z>4v(5y3diT@r|{1Lyz>WfoWn|BkM?dLfu&}4p04oh?y`H?MivmA_DPz3!7GE{uaVZ z>0~5s=CGMjfy#ZEYRO13`KJ=AW&SL-z5WO&DBx!}5D8=Sp43Pn-4;xLPiiLX+c!~H zhS{d6Xr09s3UN*8^q4TAsWd`g86}I_$woXi7=`DXTJ3+VZoAUZJHpm>WlI-rto3c> zNel1W8pr#$@_av;pa`_9ifn8n>*|6A!k$@|ZBqr>6*)Gpk(1*-fVf)UmI??76+Vpu z#DQJY{9C6@>nG#2a&ASVLZFTmWp%}fBPWP=ZLrJ2{zqPWmpG*dc zg0MD~ppr*mn4AHzYC$c>HgXtm_3yA^vDSWKvHCOwiXSEjG>(Mw$;d^%kVU)xW}p<^!xR)oI|$0R%SgVg#SO|AQedQ3K2SOI%fnNOpw^qXc=p`@S7 z5B4iUh>)A{4rIc<#h$D5cU4sMOGRZMx9{Oocx)8*)*u*UN}9i78c@!<*fWjCsv^5} zFn%+9Y$0^bRp#$1GnUb6IZLDvIW$1TWUKU(**7YV5~AcZtP}=(Iu7`BpMFZU4|uYi zJ6edAhnyGAHz%2ItA@GYP{a6aYTv=9*yuLe_D>j7CXlJn8s|$RW(kSgauO8*swX4Q z92@1Q%5mpl;fFs@@OdRK%-?n~DyRTd|FQnCzACID$p-uI{Vh|takdTZ!mBM7E$|eJ ziBEcq-Xiq2q;g|`RSAq(kw1CnC|fH3eETN8k>{WdNqee ztdo`B(+S}zF-Zw8!Sq_Guw7iuDff^J!RX4$KQDDPo`va$rA6?ud^nVLfZQnS9?9gm zQ4TldGhw;Q!)0Rw!&~2p!zQEr8e|pq2a>BtKpQ)MXf;#)dFjV4lFRt?`W7Bu*5AkU zwq0qjZ@Y4!3o22Lw<)(N7x9!aIp+_t%>%onbqo*Lhl)H0vGsK%dO!?H8{ zKg_7`bMuL*%Kt-UjgJlIgc<$PqzWHZZ{REYrOA);!tFbDC33D~Tya^MKXYzbKUWBA zz{0eSuub=;mkEZQ>$C}FCH~CWI1z;HJKz3yx#7!QR{Iv%PlLap+|W1-$L;NxVK~YS zxa|dhRNnsX8ir#!ZnwkJcMZcaefKaN%C{4g7l$$+fqxhdA}R?0z6v17DZvVH@0EYS z1}`0kV}sj=;aJ|0VK}CLG7MKi{iJ(X1QNUfazXGHtl+>f9McV8sT-aiGYrS{>R~uG zVE!;1)6vQo{6YCpKRGZg0ttQ@hGPLBDTIE(5%3SgF};5nj`@$^ANd#TK-VxFA04_- zGK{Dl3)nC$0tp(2;h5e$499de*dl|!U~`XHh@hqH&O45_-cR@rb=B1e-7Ycz{^9p0PuH! zSBLOd0p2IPw!60ED7=3VAmviRpu`@)e*{V_H68Fj!uziSi1>JbvG96^N}UP#ox;T5 zrP==ou|s9Q1hEue3hX6vuDyT{0RBk`|1;q4!a$t};okth5ylvMjkTb{Y8&9#C&Y0L zhQSza2;pJSx+cJl5HGiqfz`3M^Q+%Iz{u;FnG#&L2yuNP#C3=emm9)cp_kfXLU@Fw z&_jS2UynF+Zv(<&+^Qr2PMgLH z&$iFeY62`>&u=p1@SR_`=h3j4CXhIuT7epavAhtqf0AbAH{R@-XT76m3iI~cv?nBe zq}EI`Xshu4{tP-(@a_N7LOhfBTv@llytApWW1GwqU|UJhL!As$1Tn zadq3;llgPf2FE$+=|(Cj`1@0>pko(f$2 zQfg(L6WTEKbo`AXh3z3Z^jb52U`>g=#q zz2J@aumiV0W`rYvN^Y^rV?7-2W+0=H7e*aRjw+~n#0wElW`KK=8QAa?Z59?B%bmWt zBi_RVuHTwGxb>PoaNWXQj2K~%=+sz=rqxed@1rbRf4K)}1a^S0Cym8CZT?i!w=d=` z(8zPwSf1qA`^N~M9vf|s^D3)iyd|8Um?6aI{Uj5h5yDys@eokk^+G$BLoWUV0|y$| z=ai`W)n|Pf(Y!QRcU#<03X4UZ-BO28;Q^N*zsZXRTuY%>w& zfE5OB->q^)Alx#GNZ;Yp`GtQ%Mg83ZR-HE3Anh$b1f@;yj+K%u zB+uGY$NvSZu_*$XA&f>8_@qdu06YPd6Xb7|Dq>cI6PqbI)l zqdv9vw{R>QWS=MwYlBp@N8`rzdvUgn zji&Dk>rebOastq5fqz$r;C$hUKTn;o3P`nJZ9Ree5Ny+EYSDszCkvsGkRpV@)SD4P z?i~o@M8|LF3t-p*md~iwVi!lV7`;N~^?HTqc${Wa#kP82?+URS5%spNAaagoDT+X5 z`ApVee)Pdj${f-8H!#=UdUEAdRpEP={-TcckWsOGgj;=#m}y>wlj}Yd&_-y_+*-&9bHoDx%vl6W?kSE(`UdC+7 z=gIL#2k~c&&!#u8GD46Kb&E|r(%Z83+@iVG=8p!=Bdsu2;p~z;CzUsXYZ)+ zdgpnfJ5mqdR`G-Pwu)Zw?VjR}J0Q#j7m?OdMfaSFFTHarPDA+I+b!wyRfV{!U`RAD z6xlV?e(1rH*lz6@&6&!IE~S@F=5mh+D?TcwlZD@Zloa0Ny&Wu5kEPz>=A54W!j~Uy z2*2Is+@I*UQ{GkfdWDBR-aIsmW#bfV&X0XEcFyEsa|>pHZ0!dCKS~haD?bNu6zX0d zhGY8FVfiuL$_VWTbA{ATZS<4Q=RalX?LR>*Di#M3!i17_=RleT!WJqR3lIWci4Z2{ z9Gsvq5g$hg@y~_e9)zH{%)*HqCzuv)W|p$DkAOpX=`Y!gOV&A3muQCxh*)n%7SqFu zrgoYw_WctkB`4Usvzgrr(J#<=;aGRnaG`_EpHPUKG<`!hf8@E)z+4i}Z)l(0*}6Xk z4%jNbeR|H@|J^aIoMvQn6oIY$A&BWcY!nvuB-qt3b*N>}v|RxM+c~)Y5@_?HzwZGH zB~FyJY()?Top5ji8UaB$GW^Wwze}~%^t`mnF<;{9RRNtMrF$F0=XCu{c@W#8uj+Jb*@ELDl`l-;%XECFL_Tc%PV40pp>x87QvK71For^LDS@6|O z9E2^%m*3i`lW?ej->>RmEu3>;C5=3#o~;6y4llC|q=^FKF*>Ix{P~;sft;pHhEXYM(@fPs+K0or}54Cvw|iAfJAUX@a5KbuTa2zD`wZ`}Bmn zd@xGb`gNR<_1jq$M3nFa{08aJBvqeAiLXUC@-^5kKx6*(k|2|7{DzM*z@!QOf~+i= zm045Nw>B_7JoRlJO%Y!E_B_2uc>df}{vvW8;7->N!ht6TxedT62;tzf03oE;hvIRM zM++coSCCFEZ>KU>G6lI(znHcQ?DO-2Y-wJQEdd5>iM}W#-p%2v0IR9>wQ5p9Mc2R!`+Lot+BFGWk$T_K zLK;Y!jr=BF*#5mK7~l2%CqrC6t5f^evYQNc!b4tO$?-=eQ@!vf?=wj=Xy0*?FBQxx zv7L}O|pkuT0M8f9?ja1#7vVlpiV0I73}@QdKg; z?+S3l*BxUE#`mAyS~^Y2vZ}t#vz7TNn^y-Oee#A62g3pT9aAT+N!+9$oAz6I!5~R@(z<>RR7?qdMT2 zPNyCtuLU?wb$PUhX^!5`1~%wk3#gfx@&)CrGur)HK+h(YFDzGpCY^J#aMF$PB=QE& zao``3@T4^{=|Svl`J!@g45i1Vn8?K59J#6Lx4~V)RBUsXntB*dq7Agx7I&#Vv4{1T zZAlOv+rxPj?j&23&6AiE5#EyzPCU_`U}k(?2e87EVcCEsiVbjT4KzX*sunzs{xGmw ztC36Ax^-28|h*v}KKnT7Qf~Z!;1|;J70~qX>5UfE66`~g@ zrmqUY4IwC>TOb|}U6|gE5F3UN8b-!Ew&syl;)T6*y?D^aWGIV3UuL9Yua7y-%+kml zd6$s%OSZxQ$CeRdKKR1OO!=_~A9(a;ro0vW&0qLs+7Ju<@|Q<$W}$}?hO^Mld;VL? zsK1mBB`61y?-S~;&o`cvEM4cMalJ>SBGWl(%C2*gwNbp_&kj~)~4OdyS0-@a6%%Ce3U-AZ~f$VR&k(5!=6HT~d*8`@Sj zfsR8zpX3wJarpha$ds?mqr5mlPw%H5u}x3&H0q{%&W^6J@JV8io+fCPI{xd-X(_oN zLA<1=GtLQOmm-o3mkog4UUB_pc|&LN$rh_4;o@-xQg zt)yb@;0r&qA}(BN!njo{gU(XaMcl`zDm@RJOB_`SnPOk%bf1nj*vL+$Q0CuJQqm8% zqXO-Aup)7!9Etlri#6sDQ}^yhwOBLDzcUSrmDn8)X0k_Gn{A2THv5J(cD6i<2{xq%thh3`ks32}h=S>ldJYNcC{sn4ZF2MeRDljd-Aav zpgV-i$7jG-Azy`)`_myP+a&8Q!35K8=8hxi7}jUo2~oB?un zh#Q*ZZ&8eW8yxN!$QkCuoMJ;fE!XM;R5euzliDPH8Bfi24iP1$ZDsw+TNR=%f!;#(;*113QB6&I;V83`7aI~l7T1dDi8R{& z(#-rFV{I*0h_ywcy)6>sxV+lX@+#$h8+h~-(mTT&BbsyqdJKVg5DfW{&kK47p*s`C z;d)0dQ9HQx5;UN0Cs*rRpA60%%8|hBhdhpgw8#T+AtT*Ld#C_h_gH}5jnQzpsHyR- zOUi}y-%^I&0SvqaYBM$&W&g065YL$I<1CR)5wJ%!1hh@y#&0QT)q28Oto{tx7uQE~ zld63xy{btq6nJi*p>o%OEhw|A*3X5rfqK;!pft$Tfb&JFEukd=d>{tDNWIFrz$ao? zsx7f4QI7dgI=xGrmqaJrqxO6V6=0@do|KjpnS#rTyQ&Z6N^40A<@#|~9=fMlQiW7c zsl-ivtMtttjVEl!d1;TM%CBDt@4pb6wW=^oXuD#yh(9IKF*I3>O{R}z6;$n*rU9w` z!yegR3|yDYPP4ppj!Kz?Ge=z|Q3jj1E171h)bbnGiytS$=C1Q-+*((H4V>8QlEm&g4GC~Uu8^VR1>lSB}|w|TT)Y!{3hRrAw@s>cB-}|Hzv#LsqG5f z5pBh{N%PkMv!M^K=OX!VXWJEn$sho4U=@u@r-9cCPwr3S!#uIhIDQ8Yi)y;P3RX{U z8Ti)IKho*_$_XVfQ4(5WcIcYcgSTp_PdP#7j&NnzqD7!ADeWf(=whaGmiQD5b;7zU zFgmGO?Npc}x5c->G6%;&POEZiZ7I$a_m?n3j!LtFFQC9+)7ny7H;o&?MLem6!xPT=&ko6q^ac`n9QC>&gQiJ6@XAK;6l=?PCmHNA; zlZ+A`wnFsoF%`jW3cND_?6E%RKGjYb+a%{Cnd_bmvC;!F?PTX(HBE;|0=tSe(Zbcqk5h^quBN^1sQg&ovH+xlcMYNdcDEqk6)LrUxz~WVm zhu*{fQ06R?t6em>^&<3s)}p~J*D`F)e5N;;8-|YkxJL~oy$ts0j={Bo8JgPCr>wg2 zE-y$p?J74@pn}T_>)_6h+WF>BB;ye;*8h9&;lTB&Nb%2}wkz|&KXOx4X}+J#K~`Jp z(=k}R+Gc7rx!#vwu)`F*fMsxpd!ozCpsd(h=HNvxosLrLTM=(86N}R6gu4#~7&Xpb z68PG|cp_V4+iHF6Lt!AEfe{5RBWU@=GM!N6Cv#za6qNZkmZ_b3q0+A|ErC?(R0&E? z+m*~ZlP!%^fJfYOQ68=oQXxMG10Sc;BsOOj75|-Pe9h}Kz-N8WbftJUgC@tw%8uJ#2b1D>rf;Ky^QUpQiJDBBW}haR zM%B3Q+FuGrs4~cA0(t#YspxxTdNq4Y@+n8}(s^b;nrk}A>FT*nGELF?SQeWPxu^VQ z|Kc4rtx8a#Jy}x%rKr-e9AzI>=YUc zGv|P6S{HlNEoK<$9fKt2g`S}lMhvE*+d~ti*!!P-v+at}vbZK3#(zU)txr*$z>EEv zG^Ymc=lV89N8^F1Y!fH5%O)Kt({U;$HYUpK5vNwTyX}g}5Y`0LWl^k}S2^=xUrsD5 z^=Fi>hqn$pE!obC4~?K%=v-$dZGwhSR-Xal!uTF2YqN)cD?XUjK16(B8z z>&w8ow(C==5%^nUSF)c*TZ04%;g+a{;aQ&==dswp%@9^jE=mF{Ol@w2Eq7b4?8u1IUhUCt57LN_XVcp=3}sfo zewMlnRxnVG*)~R|1m-~sZ6$De=6HknuWVYFc{5@Dw)|m)8dt=2WgB5dK8H5Y&Ej8j z=puW$kLZJ?PTn?ICRT2Ta=Q#=W*GV%l~GQE`=OaN{*1CjXv2m4=R-@{M%rkm@F~>S}`r- z^GdSM2||G)c6KrkuUF^;5~z6;zTJgLsx{L5dQ9C6eBxvw?QzDyHh{ z=JT9Km7WW7@#aC~g_=N`hVvA=X90f%Sy{rkTHl?~R=`zmo!q8d@g`;q8V(ll3YW4K z9b+yGuH{d5gvsaT3OhemmH-b7kmbrVjp-&c7wYnJ-uCn)xWybC0K0qy!s4(n+Jc46 zk^OAm9XtmeSPRTGBn63qIGzvPkK$YOmf;}zvz?hnFyv_lIyOj7} zbF3y~UMGR6RF%0&Q!1^VN%N5so7T{S?+!5#mt|PN8(M*_+aW5K=h_%kI-e&OoCl6p z#co!Xv8Q-m=)iUc&p3E2JqOErr>y4SJX2hE!VM%W^cD{u2gk0xL5rFfydttqro9nA zqYRoYERbndFcV%>8B(U;a4$(_`yF!)oza~!{2{MK{CF(Qvm3gwTPV#IyB5pC z@|T}LFo6w-u_ZbaW#R3PO5B8?P;iMxp)SdpBn#8CE8+DHi%)hY%i?tPQ2eZ_icHp2 z2Kxo%LJ=H!CF~VMZeSkNqGs;vj<$i2Ek0wR3B@MCB;Oc-`m8s4o-U+&zJr_)OJKgk z+92{vyFp?S+%zC(p50g#m>c*T7 zwTtvVSP?HXfm|@{sN~gwnpCqps0V(0|B@N))arZAss8sL$-omx-&c24%AGJD!! z?J0n7>btC9bSJ&4R=TYi_P1;?eH@K9PV%O^322ord(&H$mDhe=^ozRD4{Cm~W*lg? zHiG#R@2z(^$VlQp>cC_A@7o1FOwhxgH0pKK^0NU)*#tLmk75tmP%vG}oH=2;#u*DA zk1(cjeMCEoSCmh18N>$ux8UQVE?;ca!qGFb@wWjz6IuR>QSY4K)-`=)2+gQq<;sBgGUDf1|_Tra;O#HQ*~nG9%ndrvh9?Q7kmHTlf+_+?~-J z4Lz*@_VM~vwD4K|TO1kga}YywiT`y+3x5~SfWoG{eM~PXeADNs(+cKjaEg}j8V|{t z(Q_jf-B9htvz79G~|KT*Q6dWCctwNJQw!pJo?roo5r>fOqQd1 z&PiK(CxFq_!s7*~kGg*ghG6K8+?iS3VQt?))e~ByG>U=EvPl+kjf{WxD<0MYTMhnD%aRGWmmLUxC0zkNqFGJ)W}h};<0 zXWNx|mbNQ4(spH;HMX(sNnS=W`|#73Nhr{IKK z>qzm$z;*0(C8c0xxVbsNw&mtb88UnTdjZCPOdQ#L+m+Rp7{SOVqI#~22uYx+rF?=L zE5k~#g4sPOo_H+2G!N88rT$k+QTc#dCyPv9?f~RAnZS=ZvCJ&f>;M|@^^ z+ye0{!1y75?CKJf%}I5M}c=KnzF`BjzNKKS(~cqJ zOE|M>$HIvJfDbU2tZ;1xB1l6B9tZ;*Dn5b`D!vxN@eMQiFfIt8z zhu|Kty^+Fs4ajuUXKrjV6Y28cL-iY2n|re8$}owf)fyqgPs7yf__9C zM)1Ev&}amFJeVXALb+o?un6GEz6yb4r-PmB9N!Z{E2%)@x0JP(f_(KUl z!NVy9ABE5 zoGjS~c5#+`OX~Dk*$1{+%&q`s=WemK;$~|pGp<0ensS-;aI}<)XDjH$;@?-0-rrX! zCo$Ze!!z(SDdcX7ccmJ|muJutwXrOMOP)AkVS-CIE2TzVr9c2 zZa>F+5qceC*GA&pNvrP#FVN`v*SxVV(88n}B(|$$ zP!k|>xv|^zKCmsWtD@%2C2z)qMkuKv4(Lkw&+nSyV>GdDMq(S|J&6st;XUCMKdPb@ zZbLiG6t96ZK1T#-+e6i~!i;SzZ&_pc24bhBK06BBvhx;E7bTR)|x_)8)#Y<7Dx>b-$}P|7mwIP%S;+) z>pdLlIVzR89>fu5JV5P(v10pQb0v~E~WBU~# zY*{a!kX-|F_%3gh8{Kv}g&*8{Aixjh?HAfp+Kx&~t>Wu5sX1qCMerWem=IKf4+Fcc ziB}9X*)*?%bLPV@UN91cQ|zBfbL>P|P#zY@QgTj33*N6%JJ@aDfzlf1o-2!%N_b~K z^nkX`a#YGPB$Ow4uop@02)P%@zxHC&{_vank&68g=ktkjKa|k+WcMZS@RqOcSlKaJ z6l>^2LmIF5gu^YUEfpMe_s9zIyBeCPWCuDQ%H_ptHPoa8KRLL3CT7;s`_&6lPe@xb zXYr!5mX;chOU<{@!sF7e$B#=}##wps$6D|^!23M%m;Un6fj9W0vi>a@Hi#h{{CkO- zyMd#AE=H`HO~;ytO9&W^`$q5=+}>uXk6{vI!@D~hUm{z~y!$1h%>#A+X&e zA^2G+{s)A>UI!6EzWbp%EwIs75CZr61477m0w4n$P%g9{)6q2p;_YNfC}Iyn$RKZz zKxn}25Hcns1h!QWg4R&{oDjYgVFui|4MArJzK<}Ikgr4dPa$|Q1f#%{M2jD?PQ`~T zxQ~Jm@KS`CGAmuGl3D2q@y$E%q6Z9gQ5NWAuLGuV0a?tAD+O<;WOn*DmCR1>0u}f4 zENT=#m=El`CeJL}*Kb_dBY6=UC)8-sw`A;Rz0j%W7g>=3t&dpw~h&96L zIsqhZ3lEnTw@s3lPgIqwlmi39Lb{#X+3tindlxNIj&1!q<#V;zeHTs5m)5Cd?Ogvl zGK%;E>)@0Ly1IX^BV&o*w@&F{13UG*GLBrmBpnLqBgn%G1Y>21ebq;D0YCi9c&WIG=@*3gqL9gloxxN38 z?`>NB#~entsulDKbqQ`0A6*x`zf#H12i}96Z_!}Gr3g3EOUC$mPJ0(j({#h7iWFV> zH~U*lqwAZ|kehMI8wU4K$L;!UAV$e~Qp>qM4GSKf-S<#q)yCc^(09F3`k(VfK-z+7 zKmNxuxq;u`duQlA4R*IqEL=pVSB7~Q`Hg~WP0rY!Xip?~HxRgusc=PG^1f}K^5JQ_-ry4Av2H87s3@;vEL<{scMkxHOWYE&qJx{-)AI z99T0oU-FKD?PV+kGlX;q*>IZ)Z#8KHY0AemdO_pi}F!@=QWXB1SEpv_99Z`Zdu#?%90n@L3 z|J6&E!bLa#9xvXtnC5EFLGf@XZ)bV-TK~ePZ-SCU`4bzTo}60lz*M4=!!kTA$ukAO14i$S(GZZbF9T|1` zA=m#&pu8!DN!!;`A&yu|Gm=#@_d!xUG$Pl|l-``0q~09ygQc`6-4$$5 zo_t4PlqbQ4bh+>)TV<;%|3kHr7ftuk32?7Ry!}49GPq}(?xzn?zxcxaaIrGx;KBQ8 zA2-R0yCm##l_BUt2)pJFAs83h1?8KAKsNz#IORMpe)BN!Ju7a85Iqj}I>@#PA>bQA z(1j4lam&X|`82{9*qjl@>11Dg@rg(1LE0~leUv`MjMIqqwQO7%5D+T_{8fv8c@#GKB0cz$ z#);v}sexIc#|>RE4(hr~{C*jHVs^KH zQhv|jH{c7wa5Zy1(iGd0%cs;46XLs*3cxpeWI`}LwfxpPGV1T$c>Ugt^koo#Y_#}V zJ$=upeO=Yk%HIPY%FI-U1#DWznZ_%dU*N@cD`+O2D!#UYj;1-{7c1xr4!)b0E>^Cj z^HbivMsjv{v;13dyFGUqFg37aPTn(;M?t((JhqZ<3NDddkI~#)9WZdH+kx{jaBTP^ z|AP1-SQo?b>|yD8NXVghQBJ()ZbmQOx(W>5YsEWO(ZBN5kcL+=mWH7GX+ZsRqDb zSjC5l9jobRj$B;p5PMhC7#P-p)o`G3J3O6Nf4-u+s<|YT&gsUFhJw>o#CK=lYX+C7 z065DC4%jpFjpw9aUVa(AIZ4&Yd`>Ugj^g$(-S~cOZ{wFP;^Zr#)EpLwr>3`qm~yXl zc<5;|e-fOVT+?Rp>Ht+|$vN!|MC|TUac`9;cHas2(&F||&x=yL1B+GeoeYflBY4Ml zm!p-+DsbvC^3R}OSj3BG4#QD;Uk@?;#;d6Mrx(n>kmqN-Q4s}qEg`TF{C^bNts~l` z4OYdryACVgQ2ai5ClP5gvrUQgQ?IY?h;R2FP2p2P98Cjp)C2~fk$kc{MHW9WZFq_T z;w@lO#;Pz)@XwehPcy->G)o-w6nxO%C@y-6)<&ibn?>;QN$SC4Pf-uecjBx7_O~Mh z-v~kZW)ZN{PY?&TdjTOZn_mvT@C=Rn^#dyC6@Ks?J53FK5k{DNFkC#cl2spEwwA{J zdN1aCoC!OhqaVi&-H;3e^HFX8-7DZ`mv58qpyPR3%>)|`*PIVd*i0Y(^)94*spg%n z^plv3&{{qt9VtkIPZHEd7xChbm*}%May|!=!tmQPMsZ>@T|1^w8fTepdtcf;PBBt( zMmcb|tfl7o`G+mQ0iYrBeT}fH_oWTv;Ue@;&GZv)d+Ek@@lV_6{3r!nkv$E0S>X!F z;kA7looH&IX7gU~w}s<{dYYthfcB*|$e9>VCE$hS3Bakur7d*6TD3#n<^s#9c%p>{ zZ&2c8?t`z2bkWU2l+i{P=Z3+jF+ZU(FhKZLja5l^|Fy#iEn8a7_MKpcdQt~H5&zIe zla=pFpA*4Jq7&}+&%xML61Q@Y^b zzP)e_A^0Krq5`o#jv5d8_t90M8}BfO5B~6bdj3}m{0AZ8`F7f*{^Q`r|3}+*fJarO zVc&CS?xZ(r=r;*vLfWJ!0+N}`3<;^E&~*}0m}r_wXu9qV*cBBBdMUcHx+-==G$0}< zxR%{@6BWf(SFAyBH3(=FclqD%+&hyAy5)cV=bt<|=bm~``OeqQcg{VBZK?6<>ZjRE zYtz#a_kQ&BuzL?Y-7~PTJSYKI5aEpL=1{}?j=bG{j=WvCwxO^+VvAqq1%JVPt-#WE z+N8H~^8V15lXpM>x*=k+WXXJce4`A=S{m*|7Y03Kxrdtucx-DS3JWk zbAxbcP1J-`XPHyb_gqM{>FW(R?PsJnmz;dZ=-0Clb|?{ChZC{=Z_e>{39~*7Ey2mp zu2M2ZK|9pXpYhB%4y65^#ePQw1eC@^OCGo)k$eykes?Xj4Ezux2+Ml))#q?xeP?&y zbL?NtJB#$87lxC-2k5Tqq{6le60>Ih^sQ4-s}?- zR*+gHJ0p&VVjGqIg~@r&_^K#pq5Aqh7BS3U)4E>gha~z3-+FQ%)9;z4`=Qh~RH!B& zzttcI03U)lLv5r6?Ppz4IW!=F(4~_PbrPqr@UN#Z2I>y=;C^-|(=SUXP70USgQlA4 z$PGBBmsT34!HZaK7)^AP9#`S~Oai}9n(gUInmmnFsV%q%L$aXQQcg$jKfs22MzjlG zxKQ6dz#PU{H%R~Z7g;#-e+Smnftz0UQ_~KzFGt!7qul#e8!F}-8*_By*iJj9lYqcs~QPZ2toN2WB})RMz&nezt~UM{XRs^-a8{ zLuE%`bki~vlRRcbXVWJ}alN7y4Q zMU8reja-xfjNECt=SywOMW~@@R5TMHCePpsem`!kKDEaWBOmE(>C^I>V5?2lP8u=} zbhj;;e~nc)qWWQ@cw)3$kW2d_oyBCZvHKOaI4xwzK!j}!Ot(-#{J`J_IwT{TROyTZRDT2~+w`h$Egbl|QShud=s8 zsapE%#2X~OMGza=Exyi{58{Q^H^8fA^PASrMu6KNsm$53>p&r{TEmUQ@_jM*)WIEv zg(pKVE$%li-RLYloAVo3`2^B&a<++agBV!&90I>ECci&CpH3!3Z_7WMGX@(6>Hep8 z1%HT~bh#>-&ft^+-7egDJ9G4h+bGp`GBlKOXqT;0j)2bNB`0sfsUbf#|4%G65Jxa& zl-Y2nQN8g`?6GM$w4)t}(60Rb@u+Jqj`L8K9Ul)|zY#YJ`xnBDNL~16c7+N1A(qc`Ca1HI;~x^JjH!0NebM@MhtM(hz67+sNatDn`MoDegOr&i?R1&S*Xje4TJ$Q`{d9G_LhCAUSvr4y9oDE!u6(KOUX9 z9XUE_itaT!`i+&2v+ErCBwDn?zTQbZgtM|(j-KPa_5w_lg-U)r5dIR%NccKNaGdu* z?`s1}=OIk0AF>>u({Efb=d3Ud1`Vi!kPVr5V6s{}aXoHMzp*sutXK*IEu?x5(l3+UotcZVz-K@(P2q-(2B3f+sh-vwnX`ZLB5GRn*8H9`~0%q z#*IdfD5h*h3peDPT$`8IpO=T68}j-O`A;(Bo%Hj^8lZ^}#}`W!UL}?QP1_Ef)C+as zE?-&(v>wSY(zMaU^Gw}}YqmE~uELXR^C>m|q#w^ox%@Wz@m!uf#b_R{<*YD<()~C3 z4@oaPc^m35E}F?Rp(4r@023(cAyu*wWnj1nND7qcT!9VB^*LWx5Bl1^nW}$*?=Olz28_d%WXef z+OgIcOxCj;oq7=O$Zg1z^B#=xMjAN8_IFBHl}3Dp?hG>39ltc>xCToCu&7X3-T5v{4Ea+h zg9Ye=oh$MV_dTP2_AZMG+|Q!7nE~dTa@ElH*!0m=oE!0+-1VHuU!s=0$3`|U;ECZ= zO8O%L*-Y#{KN|2@lyl-c)S)PRKE(ggz{g^^>N)&WK@iy|l=O#-7U#&`h?v_?91_I4 zpv~cS#Dk@e9~ES}SW^2|n;@6;K}mvq{yWs3_t>bpnR@4_d^EP}P(vqfB!lifJUW68 z<}T-q+K=Hg958Ld%~IWC6?!BUwf1A!ONM3` zidIjU(p!DPl9Di;a`ULlKzLnZiHj;p5yAD{>J{QP;W)(cRNu9 z`P3!yxd9e@5|ckM14x4^@xfAjYU4e+a$w%uu!eTU>S-s$F?7Gn8L>umXF{ z_^R2?2(HE4ss8mNNMCNqv^%-<75aCt7LyboUE_|=PHufRvru;T;1>Lzfi2;G*rfpo zVPj(ElgXqLrzy2q!o?q`PyL-)ClTJK8GPwCXQ9qu#cIQeW1?! zm?aF~CY{pLJV#l6t8V-ljPjZxwR?ba#gJHHET|=|Lt;I5bTkf$B~x_DyL?Ej#~8h4 zNGuM9C_MA!L!v!L@)vt!=|lq^6QPO^4Q%j!@PZDBkZhDUMBecn5-AuG>ybX4Lt@q6 zeIfcQwjpujyT)_UIBQ7kgsutv{nyqoPLxM})!H zaZJ=O+$l;JjE;hxd=h2Uq)*rqtpD3SVZZkXQ`6MPK4p_c+-d=he1Ht_B(1?h^}?r2 zVLMdiGj^xAkl!~anXyp9`6V2%C8KXmtv9Hp&jK(tt@{FZ!(B+>aH)@Qqzco!W7A= z4(nsvqI(ANa-ji>xqjEAv|5~&WgCAlG)Eeo$@V*47CUM^KU(nCfPd~=1IBWC$MEU#7vwj7-Prwrox$XQPRjSHM69CQ|@-tSDrmip3OA#q`^*_pIeJ9v@;lck_@ zAGS+S*Wp`OAP7PDxMwUBWI^Zlwrf-QV(-=g5r;j3#!aE+GWuC2;|WC=mQWPw?{ zAq-D`mT`Y&Hg%_Ln*U82xGZ!ODspf3!Hr?9+h`b^t}$>XbX(6migsX6^@ zym50+U7xzFpP6k;zIVWExpyEwClKb}LFY`kacKDF5!~4Q-T_Na;Fe+AQ?>wCf(W8m93Un8s_jV;Gr=t4-bw4(hUk!fglF z>~B@SInBlgZe`Y!*IB`yK>zz4n>?MEs@#5id2pAev!F9lv{r)o%@I-fN+-^>T5|gR zbJS(uv4zHTn)7-)hfK&s}YQJumJeh4C1*pwCXgYnV zu`UAF0)I3s&!7gKVH0r3mOYZ?+%Vaq2NPahMPpzlF4%?16VI?i>-&Kp#A7U~=AmS|kq^S84sN1Q3C z$0MN4DL%&zF}XYJdsf0C?4;@h30+4%$idxe%MYwY*@Try#D?~{$bVe-_v-#@x=$;X z(m&Vz?{r_l;-~mv-5;y_gcK+~o_tV8zQ+x!nS-!MN=SYiTD5xF09z~Cag%d5%mYAa z!=XDYiWXN(YU%6PR^?YbPo>}v9^|y`NPyapkP%hwqU(Gl+IN=ug=uQaPd@l0hl!DD z?N4kcE|k}u(B@9gfki&qV8q>Ac;)d_iGidvW_26l($ z`3}j>?z07hB~sPSFvDmuHKmKL-|SJJDi&3LX(!$D6XaBjOT_WYm4*9ubz-~E|8;EAwTraI+@>W2FpK5GbjW&VI1c9na#`;0pRDVBz-8g@6FX$U!88xZ!2 z@pO*Vnr3!4xF2<&au++p{urMApzUerx!z*~Jypg;smDLj&{Lk5%@v<%6Kvc6Alzd! z^pt2Z%AKL7BZK@-g-XA}bw8n}1B9sO>1bbEe^}6rsx?)IP6dfVRF?e)T*ymjaz%c_ znr-{IfIr~EWLWQ`oZSb@H>D0!R2|* zh5I$znvm1SLm_JfFLEm4wk1wsfAPR;f5~y)exfsn5JY(9-hH<1`%Vp?H1aJWD#$5D zYsHw;xW(^Lqj|)^`<;(E{bOhoIy^l*O^AJ?XF}c`ebPOCn}sODJ^q`6V5Fmcwo)*k z?qv{ta*&_u7R+Da#!G42aBKsjRs~TEwBh4k=^h&_<|vD8tFYPjD2Ns^Xq&~R0>KPh zVmZ>el(voWi-OTs4E{6lPv`VD@^gB7I58cMZ$Z61;RAns4GOzcWL0*3XD69I*lSnFP-LN&4wweDnC)i4*L`P5XD#<;E@? z|2AyejwUUF5%Vq_4qVY2x0rd;x zQ{&4-h)%~QsdLK2CDAwa1{D0YF92lI;QUix__p4PLwzF521jfV;`aAEKw{X-W#XOj zTa9TC3WihbjL}Zvt^%CQGl5d*8(; z(E{dT3$-)mY$r$_GpOH{ivzLNf6~_6L%jwRGs6zx!Vd#KQ_Q`+xNOWQoiYZNg4kU6 z;RAJerHJo!(_-7K9;p;_LYDn(Mxp7r2K>Sg&D|06#XH47x`5z9GPEv&`shNj*hKRW zQ^J2O6c-0cdGrmx))!zapw=uBUB(^uM<=R(TqMfu!S23AVlcU zT7J3cQVyWcwMZdBd4zWYK&KH$S5-%$4@Ax>-HLEF!Z+*T3WQ%m_%%J;itsJy!U;W0 zHw9jWCSe1Xm;W8YYZ0cVQGEyKYe-LYr@F*cgLZFh0(K|}r-xG@xZ&KI{ z=s_jq4xGfO!@q1)Z-bwMuPtYYs<9ro`6ZQLJlh7$ZQJ_V)d`I{-EvyKmh~vT8 znx*8Y;2uNraXhJqd}RDk_rKJAkvJd3*OH%(y=6UoBl#IP^h16oc9nGh?|Qn4jPg(~ zw`fO4YAKuq$XH1a=+Qdz(WB>i0zSw}ejG$A@==hR_u<9=qA+?o0#iuwX7aO8A^Ave zB_HJo%*AYsDEX6NYqqH>QB_emy(Zq^8$s5{DBVNQAKXuZzLZT zeWzZi6(10@g6M!iz|P?S8v-ls(^QQ?TqlQJr0n+u1)1>e~D0R51v)h4Ad$ ztWazn)n$2XYQXAX@X1Ep%AzLaK{2;iO`AAEY#81NVd{2Oym3x=}D z(DT9ydI}$tdrD&c2m1GH+HDB#L}~Gyc;0XZi|D-Y-Hu4y+~stf7TBcV&M|AO{R(}c z^&shQyLNpv(7G#lV?w+%{&ymdI%5yaD43+sVVjj_wxw z71NS|DLE{y0PbSk|8DGOe%+^zQlHbV?`Os`^m%H|#W|J#J?sCMoXY>)(*N>$(YN=} z)O*u&KE0ni5S=4U{%AKo!a(CBvlNVzym&yFDvN^ym9h?(+AX1hl7E@?|4UBg|Kas) zCN&fa7(-X@TH9Esa`wk3{prvMzT6SNLy(0iA^I<0nV7U`i}Np7TPu%0XuGOs$8Kz~ zr^S!Ef46X6=$|E?7X^Ih>b$fK7J~-E`JgjF=YvjfvEjIb`1?}=OFMW7wp534lZC|3 z@;{GD{!9>+ih4?&^VIjR6qA&o^9;tPLX6O52oAzh9~(T**ty%VN$mRQDlbGhH|tY+t>(}DJ3!R7)9C?n3kJ;-?8 zaQ36GOfkd8P&xD@#((=(M_A7y-2RF0&6Io*d5hr z2=O>!(YnhJ7xg}>U?L10m@RB;=$62HZo|g_c9%z{hU4I8!2s-;wuHmdQ?_rlg+bA# zoPFtu(CrVL>KY!gO^}CIX*CMb$NR#!p94evQr*W>Uw-l4rBT7Bh45#MKt92pRfLE9 zaGLB{$ z5Fa(h{nEgZsIhKBa4!$|j~(X*cbswpRR|ez`qLr$JByWaU9E6m$!;Z^VZ-+GxZz~!+#cGSr5Mm z|0u$v^zb|I|ADZl#%~ZFgNA^E;cpbd;5oYcTE*FH{!YZv-pX#>4+pg*ZBw-Fm!clh zI?(`%XexD(e9tMtDun4^0%xhF3s+%4QN z2FHnZ?Gs1EjeNgr;#Q$_Af~i&{DZcfftZ}&x67YqcH#Jpr$I3;qgVsJFCAR89G@x{==|~Yw_wE{O7(!- z2&THlQ~px06LVoB6y$uik45>`LvI+?`^SB$ z&NOGb^Ur-j_9gzKdrA~kT2F@Zq4)I}bK0Fk;=!Iz``VqT#E7OQ?(O-YuNKX!L(1-+ zqkZG?{q86GetbH7Pr<|^kuNV@wlB(=O2d_~aN;HVpyG}j=#6w zf_R+GxXyOAXC92*JHy`C{X@?``uv@=oMWFE#!h$IpibN)oLXlvI!gzl1+{Ipn1?&- zI;||*vPX0Zr`Aft-Anw3SCs+n<(@p!{-_OCAkRG8TM7neiGL1U%M0qs)#60c%cuSQ zU`rjkM$GU$&s`(N7Y=)-|5;(mjm|^}>=DNww&5_`G$=CS++E(aqqZ(vI6=h%3-LHgotHm$F(|3EmJt-icQoE5jHXrhqtdwk7s+DCID zja&XPmf4rsuvdS);!zdy82P?N$@77RN{S{f*7Kmtq^)=?lr<^wKv9 z1^IlR=f3zW)QQ)KS<0<|Z$b~?iG|zokFz{HyafIe`1dUC-{Sdw{BOfQ<^MhW6h9m-(1`Y^Zdl8o)y}=* zRB@z*T%LhzzjPfH~mY)41dEHA3U6V*RDCE)u2w%WfJg3u3K$tYbW+} z`}dS!{oQ0DxB*glzEi9+UKopQs)=jG^+q-W=SZJiD^4^5CB&#bYehGwC*2#?iO+fz z)*R=E$?09Edt%u!_0F5b3BmROBlLO!vpbbhLKZ{$7#o*n2$spwE z_@|#HhX^qf?;DTPj~$(+F28dx)hAZH2GhKrfp@C#1=O=SiqYxc70?yf71R~n71BlW zNqAR8S3u8u1O6G56MDbiJe?H@aSGEf>v0s^im&^;J&+ZFek5d{h6YhpPg`-ksJ<@hyyHNkQkkfgO0B^TX0hYW-vY~7~Q!Z-PzK+ug~rF;|kn7oR4^+&tS}ZUOjND*rKsA z+`|0P+eAwW>14E@X3as1%o9$;gYSpYuoVSe3qS9bu^v}?2&!wn7$-f5BG;>T;*rI6 z?_UpAB6bI&MChAJNu-W|B87Yq`wirSd-$UsKSI55J2aB&9%-E9_*JHKfvk>&bpH4ODLor4w#ESpMbK1+Kp14yC@vhb$OQbqtgP5bx z{ctZg3C$yLI`6wP;`!nB$8nlC9t&&4{tdRIo@dX0cUC-aJUe1v(>}9v;J~{BCoE*Y z6OAtv3+C^86UI%m3kj!tEX}4<^dXX33n^j$b-~hXwp;22dEkKQbgd!Mu4&FK&EGZ2 z_6@da_6JWHB}@HZ6=-&;LS$l8;hVkRHCgJ9^i@5b^=ycCmA9sm&Mm(c~2w50};CT;y?=emdeUka(a)qK5hH=tXM8DSk z_Ga+`#_sQ4b+>rAXGe*nI`zyJu`VzK?EDK?ZNUev)n!}7G|PzS24^@wC?~{N9vy4{ zBy!k5XFN;&VE4NIrQ+{wfmfY5Mk&3KEHwft-GAIFhH6`Lbi}N?>>e@9V+WwUM)|$C zefV>o1~=_}Kh=5YyCa=qoN(qPHQ|174C_|s+%G0u;@q;k0=Ll|9*8u@0m=D=0=0b= z2lRDhTAcg-#=`@DhW{!29{7S;edvDiF(vbX+TMYl%+GKP8UjRSoO?{3F!}Jn^|)aA z@W5+x$c@Y+AQ{+4=$J5RMPJF;HqK<#xLKU>AU@=i5exCd{F^xUA;PhZlwWo~-sjIz zxF0WX?=x|qj*|AT^$flG)&t@{X*FxQ_^yBDjOZ?YP&^@yc^-?8UkE}zIO?Cs2PZ9d zm+Ta;9x@HEfVW&WU3@2izBLZhhtEH0FNA&Vq0IxKJHEIE-vQiiVqa&g z6BdZDtKkMk*ne-}w$EgbtL@9vsR6RBspaM$gYlY`^-o7#7sZohHRWH-<4cs2w+^R5 zx&4#NVfZ$jD#bPDxY^ZX@`$_Sga;T|0`h#^IPMnxYe60ZNXqlfMR{)1^LQ+-DbFKD z>&Y7;P!Fs#*YVrL)3n}s46k8dDIi&}_HXjJ#Lr_3Mc4XLsyg>^F-rMX#-+W}oiY3h z#+aTLPg}xbdxX2Wkzgmy>5SFlU2$<*u3YT-l?t#4*${k?Zj;3S4$3onfDNhVgWgsg zib~P%>W$!{HkH&23_W#GN##Hv2Mg?43hU&k9Q=2#n;b=PLHq1LBt&ROIPn1+=hpEX zagxyR{-yf0Pm3qc3lRG!i4_A;;ZZ+{-?8bZdtu2V^?>H#a00#(-xS~nlTb@l=s=KQ zADAMXv6u8G1Z;DrxU=0sr!UN4DYuPwq*T58cC@?KZ`#o=ziIEpMc)Q0RgTM%o)DuK z;JbiA*Y$rIv)sn7JK;ciIkpV4{St`MicGXmxslX!u5 z_{mHYF6&gMJ}Juh4C>x>n+Ap*+B7hH*Cy=UZWJ;vJk8)8R}0C0*+=tW)i$ zeMJ}Yfj2w}Pq;eX8y=4*f1fa=cc^#n5>s*E!Qoxvf{d#@nc>sU&kguLjT$5IPwe@| zi_!_F2N=3bpT>t*hqu)&uc&KkZ5Nj3)|AyPw^g^-bvN%8Co`o3#p(DR@eTCNK7KM6 z^}j`7PzPCjIrM)EN{tKo~oxV`|!xzHD|*VGGp zpw{1`eTHg}{uwF+Nnh{}81TX-^Je~$KlXKH znBXR7XQuEkQ7MJb^MUnh46cN+D#n5zt|vbZ|Kum=KK4R*I9c~obsu{iJRW-)+|Sni z8M;49_h;+ARr3`gSC4S${v6%U*Zl(BFVg)I-JhrX<+@*~`wMh`k?xaRNFBIL_g(Ni z_XtlNAR+u3rFBl{p6hlAPpz&p%)Q1vyec?TOMvXjGyaFPXV>v^*;R(TY&R_)f0XS! zK;F*mn;S8Y_!-$j2&U{TcJ&VMnj!a5yh09sA~QVzhErtzamXi%(vy%oMbU4p z4W3cT1;`qlm;=#D{S%FTbD^{n{iW#`chTSP9gLRIC^a;9P}-uIJWB%JjtZ9n`Xu8W zC}vs<$FQ>+j!aUipTmXsGk`aCn(@!>@qhkOc;hL6QiymPZoo4bTQvLzaos!aO!yiS7Mr2n%$cR$618{ssSHp)ba#1wJ#T#l6Er>whF-!!;w0Y z@<>=rXwegJ*eJ@bMF=<@HYId;kRfzjXapN(3Lm}IHX3c3ECdBzidb}Olwb(GBxpuZ zKI$^+@%|_uhAb3knktazmnh60!*eP@)5cI;IgzRj%iBMZ=?T8^3`GJYZ`EX67Wm7I zciYBL#vo+$*V;fCgVVg_W{=@!X*96FGWY>BJo8`0BQ(dTC1dTPM*=g18KrT1it#)_ zl0xppf-;1ec%sn|?k9NOel z8Y~g~!7$sPN6bMjdBgm8|Mg5##&}>-gKfA^Md;!PDIpzmXh<35I4#YFj@+X zUXJIGNZ-s-$O`~fqahxZCyen;(Vh(vW2GrK0TURejnH1I7!6a$X^B$&qkv%}&59&E zaXGo61Utf(cyeoja3tY1NQ08l2^F^_ya5y=2{QpUxMc;aRuUexkXzM2ZZj~aBp89V zBw;a@9LfSZB);t`3A52tNw_8w{g;GEAS99yLF-iLsvvh|Ho11-MoDPL+LnZR{>pYp zkCHGBFdzv#XOsK;2y$=d@wId5*~#m9m^Xa|Z}eBC6rWT`ZUt{dAf`+b{zc{}lJGrL z(~|IY8o5sX;-kFk7~mU8m{vt@KJVXi{AG7w{Yyd^Z`OC15Q$&(DhWG)sxcn?mG^*7 zNWu?5TapmR+GHfyadK`d4E4Ny1AsDvEFm@6&j+ zMG_LGkQ>8?XmtoZr_LcaEt=fbiR69?>Mscs_-nGTN+jV&tUF2gEeMz-4Cl>FchmDf z_*B~X#2w_XKgMI0^D(=Nk2)^VrmP~cx+H7`G6x*+mkqbm^9{V0ZT$Iuuql$T7Dz!7 zKAcAGy}T(h2iQ5h(n3B4RaoSbFn1QY|Ky|lI`4Npmart;Ka-o&tD~f{fm4S_Z3mGx&m_N@_r=om^IZD^EF>18+kA1 z@utgseOIJV>X9mPzZgbtiLFG)&^eNJn#uXM7+5tE~n>te&qf`VdSke zkQ>k2buFJ)eDMV_ck!y9D5dA&d|*j_kc2`rxi|4CDCYCMllO0|i{iiLAe<0I&xc~k zt>-lysH5lh26A8F4XVTVBXBE!@d^IQ7dSkR=M9?8;Xj)<=p+8(y*%gqAS#u>CvG1f zp?(X+?Blp(c?o~P1ac>3kekb=U@3>N6q#b|ZgLL|TJ%7qO@Yxmg{04u-mY zNTz44Sz3GzZ|D;|PcR3fF}#K`v;8WHO1Stt8c>FbdQZ7?O zG{%T%|C{H)4gDOAlSUpQ7>#^)30(8{li;R=RKm^JOe2%sM^G>`h9+RP(;u$w3F@gM z#|}4dB28hz)j4{-qy9J!;Yqtkz?E0eggfPvP`L4n(ImmB;PFE?9usK#l%-I@m+XF; zg#i{#bNDm612sw4i6vv;-6GO)NZ#JjG1Q{?2Wb)$ilg8r{xukG%2Ty)Q;$>k(jurW z=`~?+GvcWonGecvvqID1X79zoDN>GdDFRjpjjOGks>`jTtd2?4apwY>);W*TWaZm2 zSW@BNhQqD6iX{LFGtHp1NLr0a zc23G1p){7RIBN56uf|wNTiCe?&p z3JU#^-B$(gRrU=H;+t$00LgTcox?gc-EN>0q|zqCo@oeeF|0%@dApL{qN0|k^Wi4n zghoqg>D187W8`MJYT#b7k(xK-p=h`>l`twW>&7K;bJh~9S~vK?wbfuOrMchHlomD8 zOqAb9bFg>|hCo{KI054F@l)Ws?@or>7)U_e^l$~-W>hIiSN%+Dq2m#PscS^ETKY{L z&C0c{F1Tyiw^{IRR@n8lp4YQR8o}GyJ=B~H>~)%>F807=c$*m=-IeZQmkaz}v<4(rce)w^N6oVQG|e54(dV=UJv4 z%z^(sQ)!ZZU|AM;1MDy$Q~Hr@pke%pt)6~NmeHq#jI6pt)} z_oSFcmHknC1+yZ(FZNWz`&fL2VEVZDTWW8gm`r%(A7URh^o&@lP-lJ=Lja@F1u=Un zyp4uSXTjTJ2%#nStYI4g=L?3T+q=Eg)@Yqs#rwmuS;hi&tQ$K$)9HQB}V6X)%@Yfkvr^36@m_%7`Hj;i#dd%2M z!}gT1fu{5sV>6ZLHU<$K?KjS#R~$6nLcKU_{CWwzSB;T0PA^H1P|la7c{F&3r5f^% zKsXjO2%WZfJ|fJYI^j;gX*#|CX7*V+yj$1_8jM@nlY|g%V~^3&SkGot<+rmig3UWv z9A&waEd{ige#b^5OQ;C?6-+u(Xv}FzDhuMyLc@j z=sU!_rx5+UQ>4#SNE^g!3H@&r|4xv&Nlc|N?Gm>V)Nd9usKj035zLI~e(_2Go#{RC zp#XTlwicy(4MmtyT9T&dpJ^VZJwI6=0P$xUrl6hlmf&QCAT8v}9Jrz5C}Y@h0@Lu% zP_-1%LnwIIZi0&8F%#jAm{0RJG9d%*sLkj-U-cQ;)A6FLEi|&WD*=l9#Y2WiZ>{v9 zc*_Lj{Y?BBz=gIezeFTHjh7;ROQS#X(|K^6_fadCeMErd9!8+Hi`_^Kd`^6W(!0fD zw0ic6X9>jjiNyq)&x_WX@b-(#X;NPhf2fD|nixxX<#o|=1R zRra>DGYsB4QWinjQRzH^@4FJ2t4r@mQ%BSMACq!v;@_8El;HhMdV?^-2hxL6;C(2) zMZ^A)^fHzByL4kLypN@C&G3#(uM&iQB9&2rPo)A3tn`_5j+X1^()U#77t(bET3<>V z2u<`!A=LX5(qWpYZ>0kCT9JN`LTR9GGA)_}?^e^*Yvoo+UE)S+_RJ6HuhctxA{aB+|>#BaIZZ{K)a5)2sm$K(*V-a2ke&R@IGX3 z(gc6bZe0ZL1Uo+q-bwZ@b@&Xsjyimfou-`Mv-KhHeqbXBb1MTZsS=R5R{R47+O$q= zro@}XyXf8P#WGsNUE&CgiK){#4-moIFRmk`6mk#MH*%X@kF~oAj2xp08l2k*!seU| zgquH&IyLv7GvF3nO~|eA3mU_sh0)ai;`b;};-IFM?yrSAFW3dQ><*$u^S5K*rA6y# z#uwj*H%WCs1%gyxNf5ETgYZJby;OB`Fac%9@2Rg>N9VxpWDip-u4ix4gxt)gQ~PdX zKMaR=2m73Gk+PAc5o+pUYy9ACW=@*^yV&hC#47t5iy5>ogN9)%J4228J=;&Uy<&W# z2Hva2I0DHN#w)R&r5mJM=@oZLUpe4CARVE|hb0#^Z>Lna1l}XkuZmcK;!(Pbp1$p2PIn~yjP?x>>qxtHQ{yqv` zuQW0o-aAqsO~Fy=H=!6QBOU{vrnwG3NvmM&xFWbw?~TKhW{y;@gvT+LDVr4Krb{+s zI>i~JNjJ^B6VKADw`pNrx|fj4>_h_RoT52!tq&)_wY^F6R`fOD&dP2Y!>T0&iC5lE zbJ$T%snM3yd(U z=>X#me39`M9%Q_UhZwbycXITz^sWhsC?dsdAb5!#GYxL~chu(DHfmM=dIHGu9|#D$ z*jldt*v!ZZ4Rd}yE%e9O^Fi<)$0Wgff?Z9OKFeO91^gVllv>x#>Zw03F_mWWWhPUd zhuM4@tUs|g2><+oRyh zGWv2Wn4VSwvh$2S9R*@K3o{8~Y9MgFO*}=&V5@kv0p2!oA$4ZEm@^mNBjP)RMjjR4 zBLI3#{0F^opV&%B_<1q-3V8d)BbUH?U8J2SNqIy3h+yMSV)bNr?~DJO3h!^?euA}6 z#S1h?C&eBDnSQa6(oTy%6Fi&~{b`B(C_V?Mk^UuKOF3^bd_m*XW%!m_zr`@S7~Xw` zCkaq?7`~=ad(7|_4cFs_EmT>zVkn?)?=|ctGIhl89?jb;hAtYfcMSJX-A4`Q=U^_3 zc$~0`dKVQzq#=4s4%`?gxt2cz{CJMk-&~Gx+S^oVMixzI=FO;!r(IG-s9|OUy?^#f zLIT#!3c*G$qh;&my2jnmT=%PK?aG>8Eu>|p(#vaVr~wJhXi`F5^|FSfw8ZShRL@I< z|LX=PCMLDJtJ~^oc@+vZ6z%_itw*m$ABIFhXm4+DpYp$)Kh~u(F?RH5x}#=tFLaO!gy}0tJB`9;9Z^uA;0$-l{U82T&dOKlfm@=!0qQcI+E-AAw019RX=&6N>#2%{(k-Cw z+SN3yuBPgCYM?(rSCG&kY->fbq@sdZs|scrB03fq;Cv`!`Nb7kt|IF~+3a$8o?Wh3 z!R4A$T$!sB<`+0zE?2oDw<5o!SWc$+g$rF3i%K2&#m*9!V_v1TFu!6E$`>sHn^BB3(R>T=rhD-fH7Al~b8TFWa^Q>Z0~ zOi515Ov_5mNK-PAT)rURE?ZWoSS%Kyyt=%>Rf;;%!yu4TPZ(&LC9L>>Mot=`BnwptnNzKSgPs_|q&$46| z79wAJO=BHaR9l<5HC8s8SGF|N#+vbr7u7dbFK?Hp&XRwN;V*ZTmHmdi5@&2|tbkET zRx(^g`Ngt1fe%tLLVSD@>qf>oNV=+zgHP_0k+zpL&ve`lv(#qEszQR{}iIdM(rDvUb;V>;FJ1sjSGbKB{ z62)i$N}N8+LR;N-8wM7$oNRG97M23sQZ2OT%W})}F-s+tWw{PB=Ci${ZADE7I^eFZ zp=Hh2oiYg9iRont7C6+v(vtH0g|7Me<@p3`Knz)yY(%39z@4kDuD-6VuDPbp+`gtM zzPhoYx*ZR(a^32Vy0&J#fz~gd8jAI#Bfh$$qpe}tijF#3O&I>_Mg?Ul5JMGUO?p5^ z0~CS~4M41AMXq887L&77PNS7uT2V%w*0HJ{((r1z4=}l0C1rL;nXA-Z>T(p@^R2WT zQ`3?O3}`sD@kiVW5WMBhb+t0cfYyqPG(M{OkV1i=LnG#xFkfMQd4;*Pqm32{d4z00 z)*2hy39q@Fg%vI=OsoI`eY}8x5$(?66OOR^dOXA)+v zEcZn~ST~h&dOqQb9GZ)d}~`vM@y_s&oX}&>{#x(uJST#5ngA{F9Tt5p%O=V zId4Lt1}z{6oMFLCAiz-2Ox zss~AP%xzhi=^XmgF)t_l02dDl;^9~YYgy4;i@6`VoC_WE9iXk&3agCC=aVN# zyWP=vCX$$Eo$qj!FDlLjMkp$^mN{J3Vyw3X)>2n8h8jI~6*@q4wZ*Ihs&5oQs{$~r zu%oh)a^P$oOfd9Ah+;;XP!8NnXog0x+?6MT8qh>K=DFa}#O9X}+QWl}G6AGzj`GUF zi$N4j8hAi`M!*v&PGfJJLp@|{l4I;OB5)E07cU0p4Bqm|VzT2<&Xhf{rBVnt=8 zrDbHMrCBmlGcDQa>B$+%=@>d>tF5lBZF6-H%L~pQ^GYj88&ZwFTNXN?lSAPK#E!Sl zY0U?WRB~1c6v@ShQiFMg4-Tf=Rgd`rtsWe-WWnyRRn7rS5%7WPIl*OClz}BHDzOtI z>RjNOPpH*ekqdy-nw+bxMq`b7W*(ah^qwl_oek3`nRF!Ui6=qnnI<~_VRoa=g*?m>eYsE3a#wo z68#N)E#eJe)dm?v58tNqhvnrJylWtkC|X{mGalGQ0%Aa8v9wVGEm!h5HqfAV2sZEl zv;siT7M7#PQ8vd>oV!Tpc?kWis;j>8*C;PXo9#`&kY#lG4UgpOIL!y=FywU0Xw~3{C}$3uQR72j8=LqF!O<6_&<-6ck(u}* z9dQ#XZ(Y&Bk=Tl6!asGjv`8rqq|Xx(FOx2yWd)}VUjEcpnO|4|>W+n3USS0cm-5aM z`OA0Yy3*6LIq@rWEadVil>-CgD09p+H&tH|-_(FnBSOv-Tr`l$8L@JltjC}$C1q&% zrL&N$NvXbqbMaahGZm(xs?-rTm%)eyB22-lAMsc7D)Su`u42yDVIFuxW#}o|JNTe^ zq+Xvf^F(oWK^rn!tmXL%Crm_JwN*%?pOytt#9_aP(eov5ZE0DcaiCPZt=@_9@_Amu z>0$J^M5&{wi{&!9V(xAL|eQ^M+`sRYb!56Ft;phuXmlyPD^-+@8 zN=ir`^wE$&Sg>0mN$I3zP*C!8QHG|ZLMh9)RaQ9of~js?RlTMiv)~0D{2rlk{0+EiZ88mI0KlrTMZsdFIS)edMXZB#AhoKq4Mfpso{&K=+9f=|RYX zv?hF~%ZoX^3L}zAD!gycAmO1Rud>KS7|l_(prot-FCc`7vAme$x|lD|NJFMFugXaw zol~K%!9sN&V#_Ixi?3;YWplC!CK3Qw2*%q^Lqa49+<-nge3^Kc9swKYgp#3IApR2& z%Jm&`vV{~18jGQD%?So-5lA1DUDmQPE9u>!z@iS3L`MUpfi`qFh|@uZYi2l{Kn}1L zm780u+p3$mC@6a$HN{45Wf|30=CImb3(E2<9HcPNcwz<9q>G<=y_&KI1B!R$a)<(R z=(7t->@I0OCmRjvY8K$TnpJft(j9Iib|PKWXfeI-{| z`d~KC8XJn;H0sX908Jo)hJ_C<_=F zd33y{pVxOK%Ap3yEw3OgjSpTeb5vB86?1~1V^v-6>!aayx$427CM19e*2gMP;kC&# zWs5vp1}bd>;QFe9k@FJSjKPdGPv`lOy)`b5b0_Vbo8}s2u28P=DwVYapI4&l8n0$q zQ!t=T=ohdT0+GzKO~+NM4Na|$@heHF@s;wB3vndEQTm`XCr9VxAX3Zk<$gI8^~jq9 zhB{g0kPCeU7yi;nepNKppqIjFq|pmm9&$XC=Y!_n!^@Ijs4?a~WOA?)FE5dio}Nk) zEp?l;4j?|9!&JDgCRw;@MRl!A4h@QnL{T3_&is->YX#{?SGHhJ4=QzJ(IL4!kN6{^ zPXIzQ*MX@i^1~@QJb2lbIqxqiFARW5hUuENrN4~vYKmm={XiNz5)&A$UWAq zF(Vp|k2O<13@1quPKOmxr>p27@~*4{Q`5X0f+4XG9-dbAUFn)C97)O`v*+!T59L75 z`0^^V&MC42&^3$(cBFzxBClUZcAA!T$okib81%`WjTXLBMGMfY$5gm1H$;(1&DJU0 zpk{|=mqJ{D#}#&5y7K6+knF*5?uOdhI+Fbd@tTXo!Icf|4a*uD8#>mI+Cs|}9joxA zM7y6>TfU~Ap&e0+g(lPshJY4d9`Bcoo<_o5MK+-H1yCLR7lhul4ETIi4KS^u;d4#v z>BVncXoA&2W_nt7T57r_DEIUQWou8@fED0RVp&L?@BwFoPUU;wdF%Z3;CQ5 z$_LP|K|2LhrV!IfqlXdFHAmnz&4k$z%Lj++6g%41xTLigRB7VFNzzKMt!zYfCx23 z9-PItBHx84PA|$tpNYx;7Wk< z!i+TJ&Vsg7halb7h$|J$kVS}26J+_u1IJN{Mj$j<9IPkrsZXzDGx(p2Benih><~pa zSLK(NE#R~}nc9LJ9+6J|cV-gh*3wcc0gQ?gG-*Cs+r;E-CB>4Rl7)>FOJ-Jb3NTzI z&6qA>(HbGNMA8=Fe&2<_R}};!kVqHb+Z&|U_1Fg{s|@f{`Xh32EXH?6hU|wZv>~GH zhYaqJd$`W|5Uk7Q&>kkbs)5mvCE**zM@_>$1gdkaMHgWnUxt2pbyHKdi*U7qM{X4| zSeK95P*?DB6@Zt8_d)9#_c4gp^}Uy&prq}n@EuouXIE#Qh_Wj_v;;w)x?!1tOPgmskC;IXXf!2|qKgn7K%z<3 zNdp&KJgNalwx;0s-Iwv%mEpSH`Btu=Bbe~+Y=cvA<=gY;^A>3FrMWbtoG?`uE0yI? zPjL+jxHni1=%zgMERZ>t?6Se7q4C&HKpy~Elei^LK{)~C1e*+cd?N?tt|3&AOsvd_ ziHY1uL%GOGL)X0yk~AO`62CkmB|4`8S%n9_rgAugT;K~}fc9z#FimwXn1o!kfk&Im z|K|Ne+NmKT&aK1PuC1-5ZBTXZSzQ#1rH0XHtAjOObGxf!RYOgk?7LDq_cbILYXxoM z!>4c)FHNoSs~m{N))6)W#@6{kpAg>6SGLZZ{D)mnZINq(r)~exj+er>ytJk2;W`It z9`Q2t&-IfeI&keYV0EZ=nnNEPz&qK?d7*s}S?Ji*TNgkawZKM6`86XYpnC0xeXZ22 zRIUm0Fgt_jlN)$pJGqSSZ0Ue2PmiU&-3oVG9b_2}2AGTv9>iD?9vfVOXsGh<5I2{U zcz4kY-|lj4FFK+r2h1}5s$=C#WiwO-v5;aZ1eujWc%g?@@}BFGxUWi9;g%9y=fg3P zwn^tIFD@+LgofKwc}M=Drj&v(R5&4RAwxZ0hP8aLHcl4W>pHkiA+ln~2PFzEFu4C& zWcwdkcb#+RjC=j6me#sv@DMdEEmt%m%-bGxGEjaTG^rVjUtre*MJT35`fA&z==LQ|TY zusl^xC?TeV*yF)fW%k{wvcTBGl9r7vtJLIF@RP|I*r?J?5P-8v%81sqLqmk!W{p|7 zNa$4bM6hGJHIc49B8k6Jm!OF&`USPb@M~tEoQe!u7?BzaG+|I|@G8R0*htHa)ls$1 z|0o*bCKQdmb=nQG(ymNdJ`54~d=hAIVcfpJTIPgdgEOBL-aL&^z{RqJ$D&0ic-Ujk z<6F#m;5C0mELLdOXmBIZQqSV9Kv|V%3A*F#=@56rBLT+CS^leCb9z2-a>{o9FgfXM~7q0 zn#>FB7$`KCbTx#b@K|2rte|arg%6}2@8wWwaSbv#+TKn!7Alm`v{6JrH3&yd)r~;o zK-B`Ok>j{wLY5C6)1FDgOxPVtAK$`?rs!#Esl}cqm+|w7_!4HO4h`KNy{J1L)U8h+ zH*C<AQbknMH6jO}IG+-P;LX|JwrlXahu6g9)6i-eiGPbuPVb@EoKySZ;W>4e?KY?sEErV{^}Y~l@4Gk~B;herQikc|~L6uhIsb?xD0n(%>uGpx2eK@}xE3BYF(k6Y1~jMy=twBe+smcx3#5PR%oszqX? zo~kjR`NcySP?$^o3IhuDhOc-qMD+Jc{{Pp~U&$Ep|CpcDBw>1wM+qLt}7|q<%Yf-0j6LRA6<`s#QzoB_~ zBDP=1tj^c+uDZRZ;c9tlbhN_hS2Ui6q+`o#Wkbt~_GnHBejTZ2aGNLZxT3?&`hYj9)tn z`Lc9Sev#QbshBkGE>>f|JeYu1KQ)-|ddb(wO?6G+BB83mCK%{9jMrc&0j6@gwk-x& z=MM>&VtbR$-ht>()niC0xWsaqHwR^a1>(gyl85FXW9^ITNb$)5OKY4>fqH<{E_KKm zog2;Hpzt#qL#Ewh4u)LGgRK~n#be!vb|Tjh@@4sNMUsaU0sm!p{nyu|3@JlJQvSnh z2xf=2j6mJ>t1VMtkx#whWrj43m-$aE<3)zFj2HP&ErVjxXS`tKGDDHC1*mxhN`gA< zmx6GTS$Q6oux1|x9KttnxxArk5w(5E3ZOGO3F#&I#NYe!@mzKS;m$A4~@Yv5{dkO8OlMi(EAz7m- zgQ_JUx*?-!rE@v|r?zhajH0^wpPktxn+HiC0RjZrkO%={++;T|LA!Yk2?P>e3Zf00 zO~Qh_1XL7pP_YF?3oJN<;G=3=UsX^nK3b((>k|tqtrk(Lwwk418!Wb4ZR`Jc?wr}3 zT@viq{=d=i+xwVv-}jz-?zv|$j*WXc5eJHEs(u@J!;wgJlwas`dRfa~ zCNYu5lxZ?|=ENq7P79&s{8MBAyFj`RfKx}o^%%LbdXhRH-}P#Bnzz1K+sV-U2mgVW zBR8sIY6GG>+Q^${6cFHHcElZ0V`svbNI_Oy9d+hiVC+*!B0}q(SPy7#Q-}*tlt!%9 z6)_ZZ>t<@Eq6DtZ4UN#C?oG`of-w+M~d70V?XYY)U9#!cwR@t!dxjJ|6XSwdpTCw-BIWu}MLLX)>> zt*FNhJY)PrTMTy)aSsyV)ETjooykB!aI>QGObNR<%Ho0>SFT0V8p5IYjd=N7^eFWr zL&p=fG+Ubk<)rD2%`|`UEGW1oLxI&?-Hq{2<096FcmTeA5WV`^*)A@jk9SUR&Zw!G zkJ_g>)fkrsk3wxkOF0@ti%Z0c{==sj>SR+x!g<=c(4RfewhjLd6-Es3A#xi0f za~SG)P9yHAKrfc&aj;UXwT*%pJ|qiu(soocr+2e6nHL3x*c;jkrpzqV)mmti_c=Kka}zQhQIL;prCD{yY_iy7Dbtao zFJ9GX2wN}ku#&SjV})_@HqJ#BHT-=BZG~NUW0TUX;xT$XL;Bj$QYMna+ zn?uac)R|kGTa2w{<8;zZcS@wUNBxMm2sDr2tR7X1X*V+e3C$x@eaoW9Mf|lmvSB8h zhNxg?7cXDDrtj?{MoE2rJyv+3)oRT1^cr=0660ELhrrZcjQCxw?56Bph~ClfFlEGa z=~xXh5MUO;vbAELxbctM{^(LQ^;2l*3k?KPFJl4X(#4neaV}>{7ln|9<}PM7Fy{)r z<@y#dnEVhtHl%b|R}1kEPAd&Bn!D+k za+QS-pc*sJTFr$DrNK!&(m^)F>=|WYqLV4>Lem@~HdC&(6P9_DABVtIt|2g#@)wxfI<(=h&rl5?vnPv!1{J03ax`_HU71Fn6 zv7fY4F<1F72gB@|WNvqnq&e}BqOxe3*p`VbZ;cS_i%S@SbB=CH&AqE}FG%a_s;nxk zEnpZoPH(&fij~3y2~miyLs3`kKGf`d7GbNHf<^a}T5<43W$J{Arckmk)CvjF-7M@B z>BZoj(gmq-?AFzCc+78!8lx4C%uvt~0Zro(O*Xt935a+an^@D|xZV;8r0!nZ+%kVw zNVIJ z<2SB1oGHOJw7kV}fOxmH72=8n5``8bM-9y&f6f-h51d#yIb{Um!W5^)X1 z=DtD;q23CPno@~G>LUj@42VyQrbF}CQ7pmcT{e?VFqQNSu9e1$aSH8?1M6|TQyz-sk z#@V%|7#a(Sv&g(v5@pSe>m^aQ5HZovM)OA0xD38X6Z{}w1%UP$Zs$igym-Udv{{Dx zJWMpE36u($+4(%`~b4s(*?hM>@O(_oM!DoBaYq3C2lDO&MH7q}RDz|f5S zCiU&B{d610ly-=@KB}uKa%OIqv_kVxSTI=BL8xq4=q!9QEhA@`e5z*6u|%jKgiJdGi3!Xw5!y!UGc8^#7jf%c>aN7gm86ptZ-B->5+II>=n>RT6C9 zjc!mq8-~%a!Hb+o^(kS(Axl)l4nvuQ)MUH>*Or=RG?C7uxLy>wk3nM!s=PFY&1?qbR@3>gNA zpG@-|#wm?BZo%zXI{e^4ZvHlgqV>R(YwO}#$O-!yHBc{&8fCfKFK)4!<7N&DOKFsr z^8p0$(-79uAQ8Dir$L$K&JYK6VuxfH9V)~|pY(F6Z%2*TgP8_O>!K z{%dem8E=!oubB^4B6D|yf$c{#4(jUEfvF=CZwA{?5yMWRRUn>?8qmW2OWdJ_QLHm= z(Z(!0raEU#R&gN#_j+1!ad3{fTWtvXV(gYhg&U;Hf;^ETII9_8F3`kIo62V8>rF#2 zbvPy=yLD0NFs5P4u13rmCd(~$R|XaC84-ukHR_vGT8M}kF*$+`)*p6?j>tPSv2Vb6 z55*SBX`H!8of;RKTI*($=?7Eas(PxSZxwUMh|L4I4ea*K@;N13xHT`W&()AR8q~t5 zunRS1>bIEU2O5~P9?=Xzf5=_G#(vCrJd2Cv^2{}}b%rK7s<@boEJARL<-3v8|3zZ4 zM#IEfD5@OQXC)l74jX$ys$L-zB@1bsXX`5>FIXqFzC@j*fNY$1V7tlc6rh2Pjm3Nb zOXA27MXQTswr;me+&pca05@kjWvL-uB5E=J2@Un#^GMM@Z`(ifY^lG}^P7@6@Q^Byp>|w0^ z0FxmxvKHMDkbNjRl#H<)#&%LnUV&$J5-7Hu3oapI|5B_Z&elasSG4)GrLh-~sE;90 zvwOw#EOXB)Hn`&cNkmILPDy7b)_Y1k zLO)3;V=^mBx?tw&6xVT>=P}F;_OXxVEs-IAG89LtufmR@Sj|Yfj=*hWnf#`~NTAe>ny_RvDsJYoFGNlskfCIX9vNQdG& zCu@8%Zs@<^Tzuk0_(OItUdNuAq(9E}U`}zK&So%Z|8?;!Sd^pX5z~T@1mVsct_1t( zpm9~vnxbnuRu?UY4Zv1&t--bO6=Zdc!V9C`8eiP=uUNJcVkcM*ZC!~hk`4e4HYhT7 z=40HVT#|dH-$fE27HA21_=j97N0B0B6sy^2_OiFR46M=9KRXAG=?5!4!JR)bL+ z2xn*dkA3u}bzD7Ej~Z1e;?o?1`Hf~j zCuGIOJZ7+HVgidWy@EqS|7#F-_GXi87Aqbd-$nHB4F!737%BSm_eiM86+|uFr-4?gqV_!@^Y}R zQO-#)tCn?GGervqi@M6Ud=X7NLirpV!m2ez9m}DBjw#7h$u+{9!uwp5D9&HJWQ^|F zP|Bj}7xOxePRfR%jg9vVhsG?+>;_l~Fct^%8mZ8S!gOLNkfM@k+QZ6YF&6{l+R@_x zQAWQ5Tp6`8KNyXreEOO+e?;jW1Yd(*_hqXP?@arj;r>cc5HSZvvA^ zS1{4*P0p2ume5%;%-=!Qx6B9ocQg>$TVu0$Fc7*Ju}zDvbRfa{gmGs`kwe+&A|v!| zTc%;%F-`jlL%&#WVc*xV%ZdJAtPO??H7Y;RA}YNkPyyc=Z%T@C#A{tErGah+T>x6? z#BM}PZ!jl37iKdrf(fQ?JjXK6FNIuS4%#1#9%%s7i~Eaf#O06KI03toR1mFwV=h#X zjVtDqI9MN6z7`6Mv`dEXmCNJht1Mm>{+ME@L1NTbwTS)pi1~IQ&cpo>(yGC&Xqs9h zm2PmHLI@+S#EFA{wgpQn<`!LsMx0Mebxlo1|3I%Ycv~h)RH+MS!s54iih5DCp&Lpi z6dj5!M?zD7jSq%UR*~ve(dr_)2D{EMdloq=cbZ%q6}fOV#;XhGYKRF|axK_MY|Tgm zxz6}@fI6R|6ybWkX|=>KoWjiOczP#hb_MqbTilb@Qw?%wx9(?SHY&&oUFkAzh{Wt# z#8qeOu0^w2K&N{O$f7tHiJprX7s;vVi19V{2eedKnJ`igVuKLWSS*Sa=Ltq*VfSc? zSnw`H_LO;?YiNf3JNQ}0hp~+DDFasK#@Se#&$JDChG|d;f%-KJ%KIBME7ntNZj4LA zn(^rb6vxbUROB5~Lb~c+2U8&P=8-)JQ)rDD10qN2D;T4^k23h|xD6TYKPhQi=nYPtuEnc(+i{>&_R-z(gLt(?BRuVrobGL|-p2u|y`T_-)k5sX+!fNfUS7Y(Q)(P%D zb8g(GGXR@`3kY=V~sy}P)Jk&N*ec~!kVW!1@evuk&Kg@Xm+tnEh!Thg-P_&YM9$> zUBl;3hSNHI(3M!ygc6Nw99qR64$yX}b5-m`*8c9d@{Lx!V%}dh?zd{V5N`3YgpZFJ z^rMeJkj`whJBR}Z{vw1Zcr-|i&MNJ)CYr{RjpvV2=YXb8aT)%xV(TSX|cxG|W@fX@m+4Shx7TKwCwS z!9rw;L!;V9-^`Y=y*8Zl^U;4C3tmX(J))725i_2s1>&*L=T@~soxV+&&BNrldYKcp zlGx5w;TTx_I$!)Z29Z{*x<=d>v3z=jgfwI(L0C_NdLNX#TJc#FQ$-s4FPMoJybJ85 ziOW-XL9o6N8|&uW7=I0@&pkGs>iCu#Rt?Y?qzi_|@QB7hIyhh9YhrMq-PpXS<*=Q( zbj&a2Hh~4))DCBu9un%}ID{~-U(j44F2%=c#0hchM2{3$arH9a@@vFrI>4aQ`P;<8 z!fVEhZxjHL25(_#mk3S{>wg<}fXMyprn*@$Z4A~wDt|EzZbr|XAuGZhV)|nOLGH~d zJ~}J7H2MgPDc&^i?nWesBsav$MTIohD`S_4zT8RsgQyzKzokWUrU{0^PS*bbF_hh) z{>|&$b>JrYU+B=V7MTh@m0(W!kcWtwz`V*!i?(KE2CTdQaq4t>_n-6m;_UA%nlnPC zgY}PCScnrMvJK-Wi3Os+L@2ySlChp{EJWETu~q$Mqj1b##aV}I)p*yA`}*KOnuOFd z=G+_K>muXa=uGi!k??1p)|ALabi?_sxv>kx85-Z?5_cofK*ok2hZI`mGe@SE=zM$* zL>*7C`3;zwBK$*Cm~K)se8d*sV57_phLC6A{LtVTMG|IQ;}lMde8+~E%2)+Px@~N3 zh>Y&v0yBRGmm^d)7Q+~zIgt_nV5}M-V+g2?kC>dPn|URsa9V=tI}ia>E#9P!Mm-sr z6H5V2h(=bxDp|Q)F^$l&8?l}cYp{o|t3_rY41#FxN`k%@&etS-DpC3xk4=)VOHUgh z;ZuTO#loAbJRkS>cG}_|Ar_DeQUvacN@$S*mAWNtu zjTG_CVv(D|Dci@&1@d2>nnZHEeh*66(nE zXo@t>;-nXRac;lJP-eupBl3%WDAM>i_ry3iK0|4F6!BsDh=&FO_y(ipQ6#s;MG2I} zxhvw_`1GgcQ6zl#)$%CP1r`_4!^bBh55B~wNYxQ1{ZQx=ot8(D>Mbq`pAzS8jC14L zl$J-4@EuRfqe%EDr1>Cy5X46+EsrA2wzw#KZk!t*ZM8g#gpZe69!0_@Z!M1^;e(o% zN0C}1E=nH>bV!3EUi8BzO^$KP($W~WBHbP1wo6B1-1G@Rt4E?#65~#i78`DnK4Lng z?wAP4((5tq6zLx^?o{bq*_uF_v>?VkK%(!2MxS))xfpkb^e5pq)0Z-(QTPI4^cg6% z#JC4Z7%G-0OL{EEoh^M3;~p%f+bz+hA(A)7Jyg1a+?Pk<MNWh;a{>auOnu z@neKEBgRdWUG!0;_NW8D6lsy9A6~1t^p-_RrtZ8($qc?ZHB&!GuIn$8Gb0s2uPIV; z+}rrDs^w9nREvw^)BGKM6lp-zfnSP*sowG^adVs^#ioxJ23n#Mf!JAAk+R~#@g-Qx zqr~-R1@&)z6bYZSwLFTX;j`D4N0EkET$BNP@7MAusDJCDV6oZA?Lo~pP;yFl#JERG zKZ2V&G1b)|%-aXxrh1~58*~mlUWW(Grosd658$r1xc`)(zj>1~RKo`Y@O9IIcBx>E zboDY1eHj+!BswZfI$iB0ZJn-?whFhqt*yPY1Yfyux0U%yMKowaL3g$|P+VDDTHz{f z^ZQCGD)EUsSQzSb`8vxx+k7SMm7b2a@=6gu`h8Ozf)=bYCM^}qW-Nlt2UuR`UTcy96|gbk zE=N{MedTUXm8+t?#9xYHazZfUi?6sALkXw2q^zpFv!bfahX(L_#3dro{HiQ#Blpd{O-zfcS&Vso6qC(dpdl+Qh#MxTY0Bh7EZ!lRb0{G zZm)8c`}}2C*LX!A7m|ddy3t@Qv6?1?sxf1tK4nw z_RfK4dzPS9$z^c-6vv4 z>Zr_9-0p5in7gf_)9pvCxcu#?gf?HNODipH^R(e>i`4g^C&INg74@tQ?+l?IYS8!olxVW;dy{g0Gs;ca8dGKvxSEV1eDq!6a?b7M% z@VG?^;`E$~;3;k^ZR;rO)XLmdZWO>@)$XdOsH}ihi?-6Lw(|B0qmm%?GQM_OT;eM3 ztSEPvdD?s(z7l_h3*Ew1>MHkily|z@J?L3+NfdWf`8)iT{wkNR&0W@6QPE!2>8Yyf zK)ZCnrZ+bED6>{LvZrR{BKva+g@GJhw=w@Y(l zWR!GNb^1HG9}!P3zT!(Ic9&5m%J5dXr`_!;@sxM^(7n-B{iQDS$ViUpgTOTG+!bzL zRXf#ahsTc&RN0A!uP7-iFLRf+qcfQ=7~cjiF4d}vOZ-(G9rzwCY73nW6;RdLX>W7;N-+4^%iCd7 z#^rODy8Ue^ZdIGnjblD;j2bEKaCdZ|sZeEA6`f_ic69&p(hhX(s&cKZvjcOBaTJ0p zIg#(TSbc=WzxdMlrsP?qDRok>39SAu_U;-9KUXOYDA!@we>X!|pKB7X<#r0Ryn462S?K z<%FoAN$j3Nh?){LgS{MWWGG?c)~E&?gy0T9LeQc87||0o11{k_c2_c1BYjB*w?Ml9 z8TCn3B7-}aO$e?)GzAC{114iBM_wcuR96#@lBDYhM@!O8got-5p;MA}vipaOk1;+) zm?ufk5ss0hUlOY(=S$KdLiC7V6C%4G5RR3klZ4pSog&1}6ICV>BIZK|f00Ny0X0F0 z3=CsDhw)s(iIU_dM8`Ov{Y6cli~65V9>pjzA?oKcj?hWylB5-cC6aU%`zLS)&_6|j zW~U?`j51(WIm#s5!~>DPS@mV?ri~r^HL+o%2%-sqq6vVa34pX8qVQJ64#vwFuVB2I z(d?{dlWb=H?=hN9(=FVn|L=3aj~IW<_yptAjL$Q^#P~Yn5ysyz9%uZR(d_MiX7?A2 zUlD338Evnqgh`C%D9B>B*`}k}ZMN-1cGGr@-mhT1fU%abk+GR^F5?2A82>)@Sj4!D zaW&&Lj2h$3jJGmwW7HY%WW0~@LB_`zpJaU2#^e9z?C~<=A;z~E-(&oc@%M};8Ba0( zjq#t13g!l?nPkQc#=(puWVAm;$YYOjjI<#oe>Y=8K*JMWW1R1GDbh+V#XDW zS2C{C_{R;5-(|dwG051(csJt@7$0Wb$9RD8XN)g0zRLJ3#-ohdG5+y8#!nglhw(3r ze`oxfF+nkED3x&_<50$tjQNb?8P8)ZGfW#>*J}jEfmpFkY$gk9CYUFn*Wu zHpU=h7vtTGKVW>AaUUbeBdEkbV|pg58Gpq1W5y>KpJsfX@g>IB8ILgjhVeM#$BaFUe_E^B^V_d|zjBz#NHH;eL&5XA)Ze!FL z?_|7>@j=GNl6d?-$sW%#{+#h;#zTy6Grq_8A>;2EPcoij{2Svx85L|0#5};5;o$K< zm_0@?<}r?AJeSeUSjG4)#(KtSj58T8X1t8i&$yUzg~mUwWL(F11LJoYZ(|HHb}`<~ z_yfj=8TT9C6T1QOL+DIit%q& zQ3WS(A!9w`e_G}J(Q9J5XnJG+-=6?t1xM^p5OFJqZ)g19*8q?Ies-t-f7~W0oBgP)aUPg0s`7d@S@J=X=F^h3Hqq(OnWcPWD<%|~)()h1q z4|6j)i{0}X7cwqlT+V22BClijO^mlNZe!fV*w^R~;~xSr(FsR0j%7TT(Ze{2v4*jc zv4!zs#&0urFfL_W&3G;24d(dY#2)4-xP#qyGTzVlFyrHlrfB9MyI*E}lkq6y`-~qm zh8Pnt|A>;OMm%EO|3|A{bgD-BA_HbZ|G%c%zS^2NpP`(dDW=m3*kdANDPt9*mvIW? z492;PmooYpmoQ$zxR%i@=y%wCn}M3NgFU(#?`3?DaWCTmMj<*yNnT?28;ox=3L!JX zf5-0682`-pSH^z|M7Hcao>LhIF`8mGC%eZn7BiMHPG&U4ZByAjlW`tnE2EICB7;K8 zM&o}C2dra^Z@YN6*;nG*@;`|u#(#eV^SP=_R;s^M^1ql5jP>6#A&AlN-_8g9)x??p zJpSXW^4~3aHP?_iI;OMRWNN>W2Q-Jp)%@am#+w*7GyY%Aj9PzF<0($qJaG7$-QvIj zopu0s)@;TRjAIzbGrAZn7%yb3H&BzB*kd;1C5)y}I>2sm5P^ivgNXI)zmd@tMsH{L znQd*%w6RT%`tPr;&DE}&Oa33XF~8qu6Vv#=g(GZZ+{Jh|;}02s%($QNS;iL_Uu8VZ zD9(^T|7u>?vlz|ZzL4FE7?(3%$#@+jI=M0a|F3G`H=K}J z6TfHo9~u8*uK!=MhmAXrgE50~2;)e`0>+7qrHoaKUdAbmGZ@XImrL30H;+`7u*VgQ zYZ=Y(@38we#vP2^jQ28{M=g8VeSq;f#+Ml1VARYbmfy0+**Xg`5N2Qbrg+~J&UCbX zhhG^t$$vWx&z=#Cf3rmW_5N?l$bZEVE&hh_NmYJW#>|C3{FG$yXM$aa+r#ckLbwGh zhVX^#-pJu%HI;*VD<)~Uqg~wI(RSq`Xqj}bkodQ+tqq@Wk&2_CK5@5wwbg5x&%X+9 zMB^;Q9Z!=2EtC5>0AYa+EOtz){E&zz<|YcQxaqsty*#AO8o{!o~S*K zToMCfK2$0P{ublUjXyj8#mAcre={Dv(_cKAtju`SlyULU0r(-Qgc*@$yts&FG--|{ zUd37BQFEB|sEPWfhxFSm5sB^YJEA1ic1?okpC#TJ3q2Y={n4Xom;|7rs;N5ri@1>@ zay(iC`ir;467RyZ#M@zsr+w=z5%*Xkde0K?eoMUSv&4JE60gRHr-{-$4~MlA?zcp& zH6r#I@28e{b!Un93roEEn0TmvYr=0>BC0VFW8=MJiARh{e@*hfC0;{c@u>aj`2>Gv z8#m&2e+2(%i8u8u@lIRf5ueZ>y^eoaA~u~RB5l*m3=*5&AHg(BJerzCJbmBgN>&2# zstfgftCXzZjPo)F%;}OOCt}b{Gcx#LN3PALKe|d8qQ85Uk}0nhj#0r!RYwA?#)^1x z@MJ`WEAr5$tw}Fgres|}gFG33UJhIX`Z)+D`eX1%IiV6zJ6K7)jJf-z;J&F@gD;5- z*`gqa6mr2u2(i-MvfI#pBHHKR&!oL9j>03LaGl7WMp3OK_J9O2*W^F0FA~TWJ%w07 zPf))3F|!^|&%Oss6$B~dKOTQ^SwaXCbfgDcTthC1fB&5yNzzKZNB$Gfd_VH~!gN%p zsFZjLbq^S~bIAYPvrxDZ6w3OfuoM)i8HobzcH_zr$-@Cq*wZJ4`$6FqrciPg3bQjL zX-J{+P-x&hnCntsdDsRD8;n_rvYU)QFaGG+2og{6us4^YzDNul(qC0h z-WRP(bM5JiLLMmeJy4rKp%8hYyfxylzlx~sm%r6htY`m^O2tj+Ua;Lg9M+MjJ(*--5zt zeN3CzB1SU)yc}~f=+VfcTJhn}9490%0X?_m!Vh|07>#-1a^pAsONr6nPDV3c%B{f@ z`9lWZ%iaL-)ZHpc_Y3~!{JY>`%|acr;DsM$p#y(r7BGvD+BGfM;`!{>psQ+Z!bU{@ zrT)96O8$V{EqF5t&4ut~`oLw%h{Q{S&~{1C3!awGNh)*WvO%RgxcA{4TUqeb;qkWp z`nGjSR?5o#*FJHFbn`Gp)%QLv51Balz2K-WsU@7>vNZPxHQsQ(H|_1&`)qa6iAnor zhV7S;uX5^ZciO_g>VJM(zQBI;Q|WoV_!)V(-un}I$sN}yl>?~42BAhOfVb&aKP!J~ zdqNE0@RU4OuC`IxDOqr>ER*b*P)(*{23H#YkBxk z&sZD%nk8Z%>Y0!~hkn&x#O~t!Fya*24)th7^~2PWs=w!j&Guj_@Zh3DJ)T9w@5t4U z_Y^Ej6n@XaZ^)wKJ%zy1&Ay(W0@F4h?-{#!f_kWD(B?xuDT^|L#cJ}l<2@5>$9szE zJA0n7we>tzf2b#?{&-Ju{eUkXxhDONjI9H=AL_}jZ|;>+4~4JWDh2P*RC!y*iJYy& z@M@ZE_|{xt3i6ePBvLjH**-Lwu~pud+?9S;N?=;R6<8DaAS|tP?r08eZ^U0^L+GZ4 z=1{PyF?3VaU8$Qxj$}1-quLa@adLBLc40&4g?U>-iD{$ud=R#`WOTh5mNLhMB{PJPR-O`@n zyH`}7gE(n6yt~=nJz-($DMxDJokZ!`QyVgJyZsAaLTVYi zjS6Pw8yzWok+faeHsFiB>oS7bC#2_T23d57r?n(^HHY3p5Bc`m#?Xu^^aIDHP_m;r^a1sn+{RE%)vSz~(3`T> z6uN!srchei=8&8`CZ#5n5ZD~LYuKT1&d=KreQtVlXmC+e$iB2D^wO#sp$zZ6SX#c5o#$BwUl%W;m3Q1Z%z#~ z1Q7l^sy*tqOM?pYRSM=U9=(3`j?^Ui|6 zxdHSBm)X!wAzaB(pH@>dG<1VS2$GsZcS*IO^ek`ahL!WYw>m(`SsS{2RdZ<6>e`Sk zYql4aH;B4djrR~r@_LVRGxdLp_gZpIXhz#?ByM-rhwSKZqq-A!?NR^HBj;0+hkA1J zsehHKlh8kM7ZrIk?>rP`MuUUlO=+fDX4uV$VuFN~_T?czKX;Crt*?J=OOVLUx=wi~M1k7wh7NsFf z#!G4FYB`G%)r?&&h19FH(@#H|jd}BUPig+3VV5KG9-HCL&L5ORGv_q;rP($h8)F~7 z2EV06Lr$h(l%*zN9({QDNk_`GlgX)vv>to@VUU@S{~rDwga8=G*)z1*WTIk=+bLihiQr<-mH=iEm zTtx}d(o(Xk;X&^hW8t}G{m(w@{hsvvfp7mpeoLm+a$fL6-XMMV%X0R>T&(WKV-phR z0{!`yWqJNlnr zk#%`TVsPP{F$pg0`ds>{%awfjl|-z+V*z)}vyHXAqUXORkCPjcgD2Fn@(s!QJx|Kx zg6B;sbbv7-eWVn9^bp(VgkPlK&b?TB<=3ri@06js`*nGCZ9=16^^S44sIbbk`#L0N z=Fe=>=b}(+FY*lX?(2PW#I%je_SAfTZ^Gf>4S9Qef7X0@m9%n7n)>r)kAHRQudnK_ zzAmq@+m_o^eexUfQtw?Oe)9NY)u|H6Cu>H$dtbn*j(El!c6>|9x4Dl!o;fl7a7);J z-g`-do{<-Rag_Yv&b2MfoahbPi}cUlke`ZF^nsK&<#qN5({R`|RKM>nd2Y@qb*O3= zY1A&65I7v(lG!Z+?S(z{Dl<&-x$N39Yu8`QL}0lO(*KRjhm zP47HgS_lFMo$9;c0_RLsfB$W{(7Rh5qNb?{A_G&F z#hkWy9!PE&%7hoIqH`*hi**ns@D^b%7ymS?lG!fdQ{$&SigiSL_c^`9&1nCZFlOS zqjK?BDX5@W!_^kGT21YyLL{hC;m1c(yWI<42}@f`18H4ORlo4p^0lG~4rKmDUX~E4 z{=Mio-S5k_*&Fw!s{`^jsLHmihUVU{ONL?!&_91)ev;mrppRapRO>T(Y}xufE0i?- zky~JO;r$h4gJGgm&t0iF4qW?ze79oK)tw*7m)L)>H#uLw{v-K(+cEv=kL1y|5B2vx zlJf_Dko4uzgW(OCc>&w0y>eC{C79Cvu0HT%d2r$}1Z|(DyFQk)a}rK{J;^r7w)@#r zQpT)s{=$Qwzj;IALzk)gypQD;(0cG=kUXZp`msDh`;bX0-Tp>rpxZvIRuZH$f*IXJ zlaf<*Cv-al1C{E~P3Rl;*|nh?2O6<5gPGkX1^a{PuZ~chf!fdw)z!WBnbn~i2O(BE zm^0VF;K1(plKxKAoQd7aZfBs&RvnT{s&)S-awGEc<4@#sE-@)3bSHM%5od(b7p)<| zArV>$-MPs12rx26euf5zMsf`*oX(Ba`h?%hUODxIzWn#{-N}*U^&x+do9v4R+IH!k ze~`TnGfDl?Kgfaf#69WiV0E-QM)fbT<>>{V%J&;R!TFi|PbJaVlISaj*oGaL{6~4K zEjm)m|0I7UN1D`YlXDKVoRZ6NWoJ9~DYtws?{=W`$

pRWJIByq4dbH&(xEpe^%2 z>1p|IW{>db&iS^Xw#uOQXA|Ux!Pp;UAJ`O@ud>-U?%k~(kiV4MY-vf(tZ6?FZ*bW^ zUsI#6{7RmowJy1N?^gAv5ciH!Z%}VR8LHLvZe^$4Y4r4Y`|Ky{Z0WnmrHFqE)dVpD z^F=Qv|CXoi4~@#N3EMAlEs^rbr*L2H^p8HxZJ^)1pVG8}DdP^B8pe*!S{R(4kI6$m zX-}=yFoOhVrsAf}e5~&jod(xSM;3&~ITwTzUA3VXR#&Uj@T&z`qwofGzIwj+m4de# z+4qr8Y5sNR_ljxw+@9X%ZF_gA!|xoi=V*A#N@eSFlDuu3I!rB9^HsBG3-@8zzVQz^ zCpUks{bXY5s!^1|)RT!){!07S`!2Qb`nxnhz2l$qrM5ft%l;{kux-_^`KR2dT`$V@ z=BLBE1McCfBWTMrvTn<}M9s{XMa^9`Z5WTe)L?4&yBHv=Ma|E{#43x0a(K5iCTGd~ zB~&P>@UbKIuHn0-?WwA}E;*Q^USg>Z?ex^g?7K=ww}i)K-Zbx~^qhT2#Ae0IEgpwDYm4n6~U<<~4kVKKAW>3A^R)tU9WTmPn0jr&Atl zQ4=jO<;TXW6VxQpsNd&XALD%$-Ao51W|R$14*w?wds2I*YYU+*{|huQZv-ScP?FWlbWYi>Lme~8@nR>IVOi6qJLvOsQ?~#?lg5%-L4WG}GPf0bO zw|Ld0lc}~#1ld~kw$E~;Qgx#0*rk6aE00;02idO7X%n&%(amiVSQROaWGCXW30pBv z2uDmeg_E$vbPvFf4J7&zkMaH{i<`o)O9^f*8?L`)SDv!HtKXWSbSKc2L61H$QJG|` z))yrz=h-$N&=Zw$cI_A7#ZthieL`3uNq-_dN0Po|H)WPCoI3~y!iWGcWfU%q6GFOF zL+FI)jIdCW?jLn~7J)Z>pKtv~FF=0MRO*j;X zXpGAVhe^`4gdnhka4=-ngawlHTgJ}_k&!P6K{uP2Oke>aGEz>6_ZtX@YLYZZ{J;qy z<5EV!ogxE&B{vfO7a(pF(7BFr3*#Hl>tMk2R`tBO$7ClioZ)>6Uk-(1yVFfS!@AjFVqMx2DZN3N{0yf^VMZ zARq4)LxO)gFH`<7WxH#voRca9a=qC&NE~Zx(#K^e<7`Xy<_u*5uhAZTLxysxdrR}t zuyi6(*|E2xHvQDzwD+-bw(YR(`2?KHo8b*B5qj{$u=K{9ki0h)=m!Cci2T7#8`MzkWHX&!{9kE;b&=aqNJNdE6fDRlIn55uQ_ zR~#6pOhLUMj-^fzexfh2N2;i#k~sgg z9cjY9NYt%koCw}v(?7~mytW~FezxLn8bmD7tu(7r{cVsOd0v}itG7BkPs+;~FO_8G z9dxGUNv_PT68u;0&z)WzxOp#1Z_meGN)o(i&NP(YHMB{;KU-Ozl6E&`wKlXNQ_mf& zT)40(p!V7?`j&EGEviGpE_s_GmRYKd9k#mO%Q)@vL;r4BI5l%G62kJsM z*3|T7)(ovRHUtU51d%3~!IeqaphC3$%wT1d!_hlhhD_Y0pBStxbbz)CTa_xkVTdv( zg&4=DPRS1JT7Ni1DG+hzAnt*;hA3lg99c@fBS)!;zBx5Vxg;@p`}PdmgaZ%dC~w%( zh|EAR56PzrW&OtCiq}Ct$*1s>uw%oaaN3El|5p3el8|6=#e7`Us^_BjyS#tM>_8ZSVGK^hU`MtUfK3REKceNbFHY z1V==;eS~Kkb&wm(?S3EcP7;h+)PH1fq+r;}g@1|ijGcOT>h|j1%-T$~_VflnT0qXJ z%?gYPj_N+92Xhrye%Iv#6Hs?EagNZ?g@0Y|c;EIay*9<(YqKjS>+Im*|B$QPIF$BE zDDXYe^a_Fn-S6w#NM-OaDoR&ecE$$BB9R}D#IUB^elIS#Fj$DK-Ej&g(i`J~Cj=*e z_<&IeCgRt|1s4U2K>Pvy+$J^5M*WJp+ zL(xJOMj$OsaN9+%H#U5ilq$T!; zZNcjyi+8Ex)f)BMNUXz0uJ2yg^>+A?Jo^L0EIal&ntu7|^>_o+hg2y4xI_wOKWKlb z0I5+pQU3jrE#0?rngvL6ON83HM{dQNw?N##h0{78(k1h~SC4!jM{~BZy;AR!!M&KB zmR2gSh}zQcS#2Au-*XG(DbH0Y*;)gne8yuF=C4{TZU`79QeU=)AGWwD{1b~i4Q@JP zHy)cXS2;(Hx+#2~#f|s<7K5Qi2IhfHHXeh(ev6w3JY{iH1~%C_Iz*)uzQy9E@Xzdm zcYpJIWvwk!pE5~VV4JDmH%U3KwXcLU>WM58|Tz1#Yrl@(zcmL`rKYazJh&-FD!K$%#WblS`?IHzS@;!v(urJ_vq-sL(UtoNfu?T4ruX!OM!W#_KqzC9n z5tvUxaJ{c^1k!@0h`(k0oRB2WC>Z&ZdJ%EKMTB5RYY4$}ZYOjjV}ywJ5F>4PD4k3~ zWIUJ9*?) z9HMvED92L#!*+x><=qrMkf(2`RpzB&2FM$&CY8RiSO2J1dBFbW-t!Ce+v}7u$;ub4 zSJ~A~s_Vehb;@{~{f{*A{!p(p6ucdN;0BERZFu+l#!PWlH_ar!9eGvvTaaftY?uRP zsmg>z<>c+@84v0=s>({onyv)_Wuof={YzE3zKGIID$P^ha%776Ln=IZq*~2xe% zg`XUm)lKnB;HTd|MR`Yz_XCF;l-rV`yn2IesOtBzFG#LZ?WY`a^Ou|d-u&gJFikJ-gtrVl1R3u_}2rAp;t!T9pkha;kCq0-Lq=al+9s6!>_~WOPU~GmcaZ9E& zM4qV5LoO2^GIIDxiL(2u#}#+C!v)`HuC>QUyDL>Hn;FlJl57f7Oo%Ypx6QB+`?TlnIe{s?_f}V*hT%6X;#mPl(1G`X(er*21ZXJ$=ZIrZ%WpVgg3c%CrGDm-tbQNkrHY@O1(j( zzCxs4J*`}64&6FqMkq01SfIW)ryj1%1ZIZQf@xxrucUQcYZ)2vhBiYo?Wk@JrB132 zrP>lib_WCph-k&ruyki8)eb{(7DC3IDjED_dN5rq_hX5SG%}!uHhI0h4xD{%8tAAs zXqeLSkwinP4&72SGEmd&oz)z2l$TN*X^Ijsh2_~4$(a+tX{J)!n^QZAh1Vn`C)S91 zCn|2?=#s|dgk3daK{Nz*wp}On$1YN8(`9t^n^Z+~^}*^L7c05kI}^Bf9u04`*$M|A zrgqdGhp?3TJ2p2Ejn-YPxN^+4P58p7NyI>Rs#Fhbxmb~HiIlVp{K7n?B~1<{ssq#` z=!MFIdhfh`lFIHYDbIZ6d<-q{$gAcnTTQBtOO#Cp*OR$vte(C=@eZ^@iefxA333i7 zOjX=FdSDJj6Q(a@0Mc6hdkd70M{dMiZmxG^Fz6pxB*;xyaEBfE-lfXNHm#TD?LqjX z={1YzYb-p4k%VkM*>h&YeLFd)2y5QNtPiSS0k;X&tuTjVXtV&Q3mnD8)^m!^-A v4<-klZR2do`i85p@W8c_TtbYJn-M(NHqMUr=+#HOX3Mwb9%%I`S(X0}aQNuy diff --git a/features/mbedtls/targets/TARGET_CRYPTOCELL310/cc_internal.c b/features/mbedtls/targets/TARGET_CRYPTOCELL310/cc_internal.c new file mode 100644 index 0000000000..5a3ece6687 --- /dev/null +++ b/features/mbedtls/targets/TARGET_CRYPTOCELL310/cc_internal.c @@ -0,0 +1,153 @@ +/* + * cc_internal.c + * + * Internal utility functions and definitions, + * used for converting mbedtls types to CC types, and vice versa + * + * Copyright (C) 2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "cc_internal.h" +#include "crys_ecpki_error.h" +#include "crys_ec_mont_edw_error.h" + +CRYS_ECPKI_DomainID_t convert_mbedtls_grp_id_to_crys_domain_id( mbedtls_ecp_group_id grp_id ) +{ + switch( grp_id ) + { + case MBEDTLS_ECP_DP_SECP192K1: + return ( CRYS_ECPKI_DomainID_secp192k1 ); + case MBEDTLS_ECP_DP_SECP192R1: + return ( CRYS_ECPKI_DomainID_secp192r1 ); + case MBEDTLS_ECP_DP_SECP224K1: + return ( CRYS_ECPKI_DomainID_secp224k1 ); + case MBEDTLS_ECP_DP_SECP224R1: + return ( CRYS_ECPKI_DomainID_secp224r1 ); + case MBEDTLS_ECP_DP_SECP256K1: + return ( CRYS_ECPKI_DomainID_secp256k1 ); + case MBEDTLS_ECP_DP_SECP256R1: + return ( CRYS_ECPKI_DomainID_secp256r1 ); + case MBEDTLS_ECP_DP_SECP384R1: + return ( CRYS_ECPKI_DomainID_secp384r1 ); + case MBEDTLS_ECP_DP_SECP521R1: + return ( CRYS_ECPKI_DomainID_secp521r1 ); + default: + return ( CRYS_ECPKI_DomainID_OffMode ); + } + +} + +uint32_t convert_mbedtls_to_cc_rand( void* mbedtls_rnd_ctx, uint16_t outSizeBytes, uint8_t* out_ptr ) +{ + uint16_t i = 0; + uint8_t temp = 0; + mbedtls_rand_func_container* mbedtls_rand = (mbedtls_rand_func_container*)mbedtls_rnd_ctx; + + if( mbedtls_rand->f_rng( mbedtls_rand->ctx, out_ptr, outSizeBytes ) != 0 ) + return ( MBEDTLS_ERR_ECP_RANDOM_FAILED ); + + /* + * CC requires the random data as LE, so reversing the data + * (although this is random, but test vectors are in specific Endianess) + */ + while ( i < ( outSizeBytes / 2 ) ) + { + temp = out_ptr[outSizeBytes - 1 - i]; + out_ptr[outSizeBytes - 1 - i] = out_ptr[i]; + out_ptr[i] = temp; + ++i; + } + /* + * CC increases the random data by one, to put the vector in the proper range (1 to n), + * The RFC tests supply a data buffer within range, and in order to generate the proper ephemeral key, + * need to decrease one from this data, before CC increases the data, so the output will be as expected + */ + i = 0; + while( out_ptr[i] == 0 ) + { + ++i; + } + while( i > 0 ) + { + --out_ptr[i]; + --i; + } + --out_ptr[0]; + return ( 0 ); +} + +int convert_CrysError_to_mbedtls_err( CRYSError_t Crys_err ) +{ + switch(Crys_err) + { + case CRYS_OK: + return ( 0 ); + + case CRYS_ECDH_SVDP_DH_INVALID_USER_PRIV_KEY_PTR_ERROR: + case CRYS_ECDH_SVDP_DH_USER_PRIV_KEY_VALID_TAG_ERROR: + case CRYS_ECDH_SVDP_DH_INVALID_PARTNER_PUBL_KEY_PTR_ERROR: + case CRYS_ECDH_SVDP_DH_PARTNER_PUBL_KEY_VALID_TAG_ERROR: + case CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_PTR_ERROR: + case CRYS_ECDH_SVDP_DH_INVALID_TEMP_DATA_PTR_ERROR: + case CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_SIZE_PTR_ERROR: + case CRYS_ECDH_SVDP_DH_NOT_CONCENT_PUBL_AND_PRIV_DOMAIN_ID_ERROR: + case CRYS_ECDH_SVDP_DH_INVALID_SHARED_SECRET_VALUE_SIZE_ERROR: + case CRYS_ECMONT_INVALID_INPUT_POINTER_ERROR: + case CRYS_ECMONT_INVALID_INPUT_SIZE_ERROR: + case CRYS_ECMONT_INVALID_DOMAIN_ID_ERROR: + case CRYS_ECDSA_SIGN_INVALID_USER_CONTEXT_PTR_ERROR: + case CRYS_ECDSA_SIGN_INVALID_USER_PRIV_KEY_PTR_ERROR: + case CRYS_ECDSA_SIGN_ILLEGAL_HASH_OP_MODE_ERROR: + case CRYS_ECDSA_SIGN_USER_PRIV_KEY_VALIDATION_TAG_ERROR: + case CRYS_ECDSA_SIGN_USER_CONTEXT_VALIDATION_TAG_ERROR: + case CRYS_ECDSA_SIGN_INVALID_MESSAGE_DATA_IN_PTR_ERROR: + case CRYS_ECDSA_SIGN_INVALID_MESSAGE_DATA_IN_SIZE_ERROR: + case CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_PTR_ERROR: + case CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_SIZE_PTR_ERROR: + case CRYS_ECDSA_SIGN_INVALID_IS_EPHEMER_KEY_INTERNAL_ERROR: + case CRYS_ECDSA_SIGN_INVALID_EPHEMERAL_KEY_PTR_ERROR: + case CRYS_ECDSA_VERIFY_INVALID_SIGNER_PUBL_KEY_PTR_ERROR: + case CRYS_ECDSA_VERIFY_SIGNER_PUBL_KEY_VALIDATION_TAG_ERROR: + case CRYS_ECDSA_VERIFY_INVALID_USER_CONTEXT_PTR_ERROR: + case CRYS_ECDSA_VERIFY_INVALID_SIGNATURE_IN_PTR_ERROR: + case CRYS_ECDSA_VERIFY_INVALID_SIGNATURE_SIZE_ERROR: + case CRYS_ECPKI_INVALID_RND_CTX_PTR_ERROR: + case CRYS_ECPKI_INVALID_RND_FUNC_PTR_ERROR: + case CRYS_ECDSA_SIGN_INVALID_SIGNATURE_OUT_SIZE_ERROR: + return ( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + case CRYS_ECDSA_VERIFY_INCONSISTENT_VERIFY_ERROR: + return ( MBEDTLS_ERR_ECP_VERIFY_FAILED ); + + case CRYS_ECMONT_IS_NOT_SUPPORTED: + case CRYS_ECEDW_IS_NOT_SUPPORTED: + return ( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + + case CRYS_ECEDW_RND_GEN_VECTOR_FUNC_ERROR: + return ( MBEDTLS_ERR_ECP_RANDOM_FAILED ); + + case CRYS_ECPKI_GEN_KEY_INVALID_PRIVATE_KEY_PTR_ERROR: + case CRYS_ECPKI_EXPORT_PUBL_KEY_INVALID_PUBL_KEY_DATA_ERROR: + case CRYS_ECPKI_BUILD_KEY_INVALID_PRIV_KEY_DATA_ERROR: + return ( MBEDTLS_ERR_ECP_INVALID_KEY ); + + default: + return ( MBEDTLS_ERR_ECP_HW_ACCEL_FAILED ); + } + + +} diff --git a/features/mbedtls/targets/TARGET_CRYPTOCELL310/cc_internal.h b/features/mbedtls/targets/TARGET_CRYPTOCELL310/cc_internal.h new file mode 100644 index 0000000000..7eb8c4bde7 --- /dev/null +++ b/features/mbedtls/targets/TARGET_CRYPTOCELL310/cc_internal.h @@ -0,0 +1,131 @@ +/* + * cc_internal.h + * + * Internal utility functions and definitions, + * used for converting mbedtls types to CC types, and vice versa + * + * Copyright (C) 2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __CC_INTERNAL_H__ +#define __CC_INTERNAL_H__ +#include "crys_ecpki_types.h" +#include "crys_ec_mont_api.h" +#include "mbedtls/ecp.h" +#include +#include + +#define CURVE_25519_KEY_SIZE 32 + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_KEY_SIZE_IN_BYTES ( ( CRYS_ECPKI_MODUL_MAX_LENGTH_IN_WORDS ) * SASI_32BIT_WORD_SIZE) + +/* ECC utility functions and structures*/ +typedef struct cc_ecc_ws_keygen_params{ + CRYS_ECPKI_UserPublKey_t pubKey; + CRYS_ECPKI_UserPrivKey_t privKey; + CRYS_ECPKI_KG_TempData_t kgTempData; +} cc_ecc_ws_keygen_params_t; + +typedef struct cc_ecc_ws_comp_shared_params{ + CRYS_ECPKI_UserPublKey_t pubKey; + CRYS_ECPKI_UserPrivKey_t privKey; + CRYS_ECDH_TempData_t ecdhTempData; +} cc_ecc_ws_comp_shared_params_t; + +typedef struct cc_ecc_ws_verify_params{ + CRYS_ECPKI_UserPublKey_t pubKey; + CRYS_ECDSA_VerifyUserContext_t verifyContext; +} cc_ecc_ws_verify_params_t; + +typedef struct cc_ecc_ws_sign_params{ + CRYS_ECPKI_UserPrivKey_t privKey; + CRYS_ECDSA_SignUserContext_t signContext; +} cc_ecc_ws_sign_params_t; + +typedef struct cc_ecc_25519_keygen_params{ + uint8_t pubKey[CURVE_25519_KEY_SIZE]; + uint8_t privKey[CURVE_25519_KEY_SIZE]; + CRYS_ECMONT_TempBuff_t kgTempData; +} cc_ecc_25519_keygen_params_t; + +typedef cc_ecc_25519_keygen_params_t cc_ecc_25519_comp_shared_params_t; + +/** + * \brief This function converts mbedtls type mbedtls_ecp_group_id + * to Cryptocell type CRYS_ECPKI_DomainID_t + * + * \param grp_id The mbedtls mbedtls_ecp_group_id to convert + * + * \return \c The corresponding CRYS_ECPKI_DomainID_t. + * CRYS_ECPKI_DomainID_OffMode if not recognized. + */ +CRYS_ECPKI_DomainID_t convert_mbedtls_grp_id_to_crys_domain_id( mbedtls_ecp_group_id grp_id ); + +/* f_rng conversion from mbedtls type to cc type*/ +typedef struct +{ + int (*f_rng)( void* ctx, unsigned char* output, size_t outSizeBytes ); + void* ctx; + +}mbedtls_rand_func_container; + +/** + * \brief This function converts mbedtls f_rng type to + * Cryptocell f_rng type(SaSiRndGenerateVectWorkFunc_t) + * + * Note: The Mbed TLS type f_rng signature is: + * int (*f_rng)( void* ctx, unsigned char* output, size_t outSizeBytes ); + * while CC f_rng signature is: + * uint32_t (*SaSiRndGenerateVectWorkFunc_t)( + * void *rndState_ptr, + * uint16_t outSizeBytes, + * uint8_t *out_ptr) + * + * so the Mbed TLS f_rng can't be sent as is to the CC API. + * + * In addition, this function manipulates the different random data, + * to adjust between the way Cryptocell reads the random data. This is done for + * different standard tests to pass. + * + * + * \param grp_id The mbedtls mbedtls_ecp_group_id to convert + * + * \return \c The corresponding CRYS_ECPKI_DomainID_t. + * CRYS_ECPKI_DomainID_OffMode if not recognized. + */ + +uint32_t convert_mbedtls_to_cc_rand( void* mbedtls_rand, uint16_t outSizeBytes, uint8_t* out_ptr ); + +/** + * \brief This function convertsCryptocell error + * Mbed TLS related error. + * + * + * \return \c The corresponding Mbed TLS error, + * MBEDTLS_ERR_ECP_HW_ACCEL_FAILED as default, if none found + */ +int convert_CrysError_to_mbedtls_err( CRYSError_t Crys_err ); + +#ifdef __cplusplus +} +#endif + +#endif /* __CC_INTERNAL_H__ */ diff --git a/features/mbedtls/targets/TARGET_CRYPTOCELL310/cc_rand.h b/features/mbedtls/targets/TARGET_CRYPTOCELL310/cc_rand.h new file mode 100644 index 0000000000..f9c337d863 --- /dev/null +++ b/features/mbedtls/targets/TARGET_CRYPTOCELL310/cc_rand.h @@ -0,0 +1,73 @@ +/* + * cc_rand.h + * + * Copyright (C) 2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#ifndef __CC_RAND_H__ +#define __CC_RAND_H__ +#include +#include + +typedef struct +{ + int (*f_rng)(void* ctx, unsigned char* output, size_t outSizeBytes); + void* ctx; + +}mbedtls_rand_func_container; + + +uint32_t mbedtls_to_cc_rand_func( void *mbedtls_rnd_ctx, uint16_t outSizeBytes, uint8_t *out_ptr ) +{ + uint16_t i = 0; + uint8_t temp = 0; + mbedtls_rand_func_container* mbedtls_rand = (mbedtls_rand_func_container*)mbedtls_rnd_ctx; + uint32_t ret = mbedtls_rand->f_rng( mbedtls_rand->ctx, out_ptr, outSizeBytes ); + if( ret != 0 ) + return ret; + + /* + * CC requires the random data as LE, so reversing the data + * (although this is random, but test vectors are in specific Endianess) + */ + while ( i < ( outSizeBytes / 2 ) ) + { + temp = out_ptr[outSizeBytes - 1 - i]; + out_ptr[outSizeBytes - 1 - i] = out_ptr[i]; + out_ptr[i] = temp; + ++i; + } + /* + * CC increases the random data by one, to put the vector in the proper range (1 to n), + * The RFC tests supply a data buffer within range, and in order to generate the proper ephemeral key, + * need to decrease one from this data, before CC increases the data, so the output will be as expected + */ + i = 0; + while( out_ptr[i] == 0 ) + { + ++i; + } + while( i > 0 ) + { + --out_ptr[i]; + --i; + } + --out_ptr[0]; + return ret; +} + + +#endif/* __CC_RAND_H__ */ diff --git a/features/mbedtls/targets/TARGET_CRYPTOCELL310/ecdh_alt.c b/features/mbedtls/targets/TARGET_CRYPTOCELL310/ecdh_alt.c new file mode 100644 index 0000000000..7077223812 --- /dev/null +++ b/features/mbedtls/targets/TARGET_CRYPTOCELL310/ecdh_alt.c @@ -0,0 +1,256 @@ +/* + * ecdh_alt.c + * + * Copyright (C) 2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "mbedtls/ecdh.h" +#include +#include "crys_ecpki_dh.h" +#include "crys_ecpki_build.h" +#include "crys_common.h" +#include "crys_ecpki_kg.h" +#include "crys_ecpki_domain.h" +#include "crys_ec_mont_api.h" +#include "mbedtls/platform.h" +#include "cc_internal.h" + + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; + while( n-- ) *p++ = 0; +} + +#if defined (MBEDTLS_ECDH_GEN_PUBLIC_ALT) +int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, + int ( *f_rng )( void *, unsigned char *, size_t ), + void *p_rng ) +{ + int ret = 0; + void* pHeap = NULL; + size_t heapSize = 0; + + uint32_t public_key_size = (2 * MAX_KEY_SIZE_IN_BYTES + 1); + const CRYS_ECPKI_Domain_t* pDomain = CRYS_ECPKI_GetEcDomain ( convert_mbedtls_grp_id_to_crys_domain_id( grp->id ) ); + mbedtls_rand_func_container cc_rand = { f_rng, p_rng }; + + if ( pDomain ) + { + uint8_t temp_buf[ 2 * MAX_KEY_SIZE_IN_BYTES + 1 ] = {0}; + cc_ecc_ws_keygen_params_t* kgParams = mbedtls_calloc( 1, sizeof(cc_ecc_ws_keygen_params_t) ); + + if ( kgParams == NULL ) + return ( MBEDTLS_ERR_ECP_ALLOC_FAILED ); + pHeap = kgParams; + heapSize = sizeof(cc_ecc_ws_keygen_params_t); + + ret = convert_CrysError_to_mbedtls_err( CRYS_ECPKI_GenKeyPair( &cc_rand, convert_mbedtls_to_cc_rand, + pDomain, &kgParams->privKey, + &kgParams->pubKey, + &kgParams->kgTempData, NULL ) ); + if( ret != 0 ) + { + goto cleanup; + } + + ret = convert_CrysError_to_mbedtls_err( CRYS_ECPKI_ExportPublKey( &kgParams->pubKey, + CRYS_EC_PointUncompressed,temp_buf, &public_key_size ) ); + if( ret != 0 ) + { + goto cleanup; + } + + + MBEDTLS_MPI_CHK( mbedtls_ecp_point_read_binary( grp, Q, temp_buf, public_key_size ) ); + memset ( temp_buf, 0 , sizeof(temp_buf) ); + + ret = convert_CrysError_to_mbedtls_err( CRYS_COMMON_ConvertLswMswWordsToMsbLsbBytes( temp_buf, (grp->nbits+7)/8, + kgParams->privKey.PrivKeyDbBuff, + 4*((((grp->nbits+7)/8)+3)/4) ) ); + if( ret != 0 ) + { + mbedtls_zeroize( temp_buf, sizeof( temp_buf ) ); + goto cleanup; + } + + MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary( d, temp_buf, (grp->nbits+7)/8 ) ); + mbedtls_zeroize( temp_buf, sizeof( temp_buf ) ); + } + + /* if CRYS_ECPKI_GetEcDomain returns NULL, than the given curve is wither Montgomery 25519 + * or another curve which is not supported by CC310*/ + else if ( grp->id == MBEDTLS_ECP_DP_CURVE25519 ) + { + size_t priv_key_size = public_key_size = CURVE_25519_KEY_SIZE ; + + cc_ecc_25519_keygen_params_t* kgParams = mbedtls_calloc( 1, sizeof(cc_ecc_25519_keygen_params_t) ); + + if ( kgParams == NULL ) + return ( MBEDTLS_ERR_ECP_ALLOC_FAILED ); + pHeap = ( uint8_t* )kgParams; + heapSize = sizeof(cc_ecc_25519_keygen_params_t); + + ret = convert_CrysError_to_mbedtls_err( CRYS_ECMONT_KeyPair( kgParams->pubKey, ( size_t* )&public_key_size, kgParams->privKey, + &priv_key_size, &cc_rand, convert_mbedtls_to_cc_rand, + &kgParams->kgTempData ) ); + if( ret != 0 ) + { + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( d, kgParams->privKey, priv_key_size ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &Q->X, kgParams->pubKey, public_key_size ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Q->Z, 1 ) ); + } + else + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + +cleanup: + + if ( pHeap ) + { + mbedtls_zeroize( pHeap, heapSize ); + mbedtls_free( pHeap ); + } + + return ( ret ); +} +#endif /* MBEDTLS_ECDH_GEN_PUBLIC_ALT */ + +/* + * Compute shared secret (SEC1 3.3.1) + */ +#if defined (MBEDTLS_ECDH_COMPUTE_SHARED_ALT) +int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, + const mbedtls_ecp_point *Q, const mbedtls_mpi *d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + void* pHeap = NULL; + size_t heapSize = 0; + + size_t public_key_size = (grp->nbits+7)/8 ; + const CRYS_ECPKI_Domain_t* pDomain = CRYS_ECPKI_GetEcDomain ( convert_mbedtls_grp_id_to_crys_domain_id( grp->id ) ); + uint32_t secret_size = ( ( grp->nbits + 7 ) / 8 ) ; + const uint32_t secret_size_in_heap = secret_size; + uint8_t* secret = mbedtls_calloc( 1, secret_size_in_heap ); + if ( secret == NULL ) + return ( MBEDTLS_ERR_ECP_ALLOC_FAILED ); + + /* + * Make sure Q is a valid pubkey before using it + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) ); + if ( pDomain ) + { + uint8_t temp_buf[ 2 * MAX_KEY_SIZE_IN_BYTES + 1 ] = {0}; + cc_ecc_ws_comp_shared_params_t* ecdhParams = mbedtls_calloc( 1, sizeof(cc_ecc_ws_comp_shared_params_t) ); + + if ( ecdhParams == NULL ) + { + ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; + goto cleanup; + } + + pHeap = ecdhParams; + heapSize = sizeof(cc_ecc_ws_comp_shared_params_t); + + + MBEDTLS_MPI_CHK( mbedtls_ecp_point_write_binary( grp, Q, MBEDTLS_ECP_PF_UNCOMPRESSED, + &public_key_size, temp_buf, sizeof(temp_buf) ) ); + + ret = convert_CrysError_to_mbedtls_err( CRYS_ECPKI_BuildPublKey( pDomain, temp_buf, public_key_size, + &ecdhParams->pubKey ) ); + if ( ret != 0 ) + { + goto cleanup; + } + + memset ( temp_buf, 0, sizeof(temp_buf) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( d, temp_buf, mbedtls_mpi_size( d ) ) ); + + ret = convert_CrysError_to_mbedtls_err( CRYS_ECPKI_BuildPrivKey( pDomain, + temp_buf, + mbedtls_mpi_size( d ), + &ecdhParams->privKey ) ); + mbedtls_zeroize( temp_buf, sizeof( temp_buf ) ); + if ( ret != 0 ) + { + goto cleanup; + } + + ret = convert_CrysError_to_mbedtls_err( CRYS_ECDH_SVDP_DH( &ecdhParams->pubKey, &ecdhParams->privKey, + secret, &secret_size, + &ecdhParams->ecdhTempData ) ); + if ( ret != 0 ) + { + goto cleanup; + } + } + else if ( grp->id == MBEDTLS_ECP_DP_CURVE25519 ) + { + cc_ecc_25519_comp_shared_params_t* ecdhParams = mbedtls_calloc( 1, sizeof(cc_ecc_25519_comp_shared_params_t) ); + if ( ecdhParams == NULL ) + { + ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; + goto cleanup; + } + + pHeap = ecdhParams; + heapSize = sizeof(cc_ecc_25519_comp_shared_params_t); + + + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( d, ecdhParams->privKey, mbedtls_mpi_size( d ) ) ) ; + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &Q->X, ecdhParams->pubKey, public_key_size ) ); + + ret = convert_CrysError_to_mbedtls_err( CRYS_ECMONT_Scalarmult( secret, ( size_t* )&secret_size, + ecdhParams->privKey, CURVE_25519_KEY_SIZE , + ecdhParams->pubKey, CURVE_25519_KEY_SIZE , + &ecdhParams->kgTempData ) ); + if ( ret != 0 ) + { + goto cleanup; + } + } + else + { + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( z, secret, secret_size ) ); + +cleanup: + + if ( pHeap ) + { + mbedtls_zeroize( pHeap, heapSize ); + mbedtls_free ( pHeap ); + } + + if ( secret ) + { + mbedtls_zeroize( secret, secret_size_in_heap ); + mbedtls_free ( secret ); + } + + return ( ret ); +} +#endif /* MBEDTLS_ECDH_COMPUTE_SHARED_ALT */ diff --git a/features/mbedtls/targets/TARGET_CRYPTOCELL310/ecdsa_alt.c b/features/mbedtls/targets/TARGET_CRYPTOCELL310/ecdsa_alt.c new file mode 100644 index 0000000000..36128fc70c --- /dev/null +++ b/features/mbedtls/targets/TARGET_CRYPTOCELL310/ecdsa_alt.c @@ -0,0 +1,332 @@ +/* + * ecdsa_alt.c + * + * Copyright (C) 2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "mbedtls/ecdsa.h" +#include +#include "crys_ecpki_ecdsa.h" +#include "crys_ecpki_build.h" +#include "crys_common.h" +#include "crys_ecpki_kg.h" +#include "crys_ecpki_domain.h" +#include "crys_ec_edw_api.h" +#include "mbedtls/platform.h" +#include "cc_internal.h" + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; + while( n-- ) *p++ = 0; +} + +static CRYS_ECPKI_HASH_OpMode_t message_size_to_hash_mode( size_t blen ) +{ + CRYS_ECPKI_HASH_OpMode_t hash_mode; + switch( blen ) + { + case CRYS_HASH_SHA1_DIGEST_SIZE_IN_WORDS*sizeof(uint32_t): + hash_mode = CRYS_ECPKI_AFTER_HASH_SHA1_mode; + break; + case CRYS_HASH_SHA224_DIGEST_SIZE_IN_WORDS*sizeof(uint32_t): + hash_mode = CRYS_ECPKI_AFTER_HASH_SHA224_mode; + break; + case CRYS_HASH_SHA256_DIGEST_SIZE_IN_WORDS*sizeof(uint32_t): + hash_mode = CRYS_ECPKI_AFTER_HASH_SHA256_mode; + break; + case CRYS_HASH_SHA384_DIGEST_SIZE_IN_WORDS*sizeof(uint32_t): + hash_mode = CRYS_ECPKI_AFTER_HASH_SHA384_mode; + break; + case CRYS_HASH_SHA512_DIGEST_SIZE_IN_WORDS*sizeof(uint32_t): + hash_mode = CRYS_ECPKI_AFTER_HASH_SHA512_mode; + break; + default: + hash_mode = CRYS_ECPKI_HASH_OpModeLast; + } + + return hash_mode; +} + +#if defined(MBEDTLS_ECDSA_SIGN_ALT) +int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret = 0; + CRYSError_t CrysRet = CRYS_OK; + void* pHeap = NULL; + size_t heapSize = 0; + uint8_t* pSignature = NULL; + CRYS_ECPKI_HASH_OpMode_t hash_mode = message_size_to_hash_mode( blen ); + uint32_t signature_size = ( ( grp->nbits + 7 ) / 8 ) *2; + const uint32_t signature_size_for_heap = signature_size; + mbedtls_rand_func_container cc_rand = { f_rng, p_rng }; + const CRYS_ECPKI_Domain_t* pDomain = CRYS_ECPKI_GetEcDomain ( convert_mbedtls_grp_id_to_crys_domain_id( grp->id ) ); + + if( blen > 0xFFFFFFFF ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + if( blen > 0xFFFFFFFF ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + if ( pDomain != NULL ) + { + uint8_t temp_buf[ MAX_KEY_SIZE_IN_BYTES ] = {0}; + cc_ecc_ws_sign_params_t* signParams = mbedtls_calloc( 1, sizeof(cc_ecc_ws_sign_params_t) ); + if ( signParams == NULL) + return ( MBEDTLS_ERR_ECP_ALLOC_FAILED ); + pHeap = signParams; + heapSize = sizeof(cc_ecc_ws_sign_params_t); + + pSignature = mbedtls_calloc( 1, signature_size_for_heap ); + if ( pSignature == NULL) + { + ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( d, temp_buf, mbedtls_mpi_size( d ) ) ); + + CrysRet = CRYS_ECPKI_BuildPrivKey( pDomain, + temp_buf, + mbedtls_mpi_size( d ), + &signParams->privKey); + if( CrysRet != CRYS_OK ) + { + ret = convert_CrysError_to_mbedtls_err( CrysRet ); + mbedtls_zeroize( temp_buf, sizeof(temp_buf) ); + goto cleanup; + } + + CrysRet = CRYS_ECDSA_Sign( &cc_rand, + convert_mbedtls_to_cc_rand, + &signParams->signContext, + &signParams->privKey, + hash_mode, + (uint8_t*)buf, + blen, + pSignature, + &signature_size ); + mbedtls_zeroize( temp_buf, sizeof(temp_buf) ); + if( CrysRet != CRYS_OK ) + { + ret = convert_CrysError_to_mbedtls_err( CrysRet ); + goto cleanup; + } + mbedtls_zeroize( temp_buf, sizeof(temp_buf) ); + } + else + { + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( r, pSignature, ( ( grp->nbits + 7 ) / 8 ) ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( s, pSignature + ( ( grp->nbits + 7 ) / 8 ), ( ( grp->nbits + 7 ) / 8 ) ) ); + + +cleanup: + + if ( pHeap ) + { + mbedtls_zeroize( pHeap, heapSize ); + mbedtls_free( pHeap ); + } + + if( pSignature ) + { + mbedtls_zeroize( pSignature, signature_size_for_heap ); + mbedtls_free( pSignature ); + + } + + return ( ret ) ; +} +#endif /* MBEDTLS_ECDSA_SIGN_ALT*/ + +#if defined(MBEDTLS_ECDSA_VERIFY_ALT) +//need to normalize the coordinates +int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, + const unsigned char *buf, size_t blen, + const mbedtls_ecp_point *Q, const mbedtls_mpi *r, const mbedtls_mpi *s) +{ + int ret = 0; + CRYSError_t CrysRet = CRYS_OK; + void* pHeap = NULL; + size_t heapSize = 0; + uint8_t * pSignature = NULL; + CRYS_ECPKI_HASH_OpMode_t hash_mode = message_size_to_hash_mode( blen ); + size_t temp_size = 0; + uint32_t signature_size = ( ( grp->nbits + 7 ) / 8 ) * 2; + const CRYS_ECPKI_Domain_t* pDomain = CRYS_ECPKI_GetEcDomain ( convert_mbedtls_grp_id_to_crys_domain_id( grp->id ) ); + + if( blen > 0xFFFFFFFF ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + if ( pDomain ) + { + uint8_t temp_buf[ 2*MAX_KEY_SIZE_IN_BYTES + 1 ] = {0}; + + cc_ecc_ws_verify_params_t* verifyParams = mbedtls_calloc( 1, sizeof(cc_ecc_ws_verify_params_t) ); + if ( verifyParams == NULL) + return ( MBEDTLS_ERR_ECP_ALLOC_FAILED ); + pHeap = verifyParams; + heapSize = sizeof(cc_ecc_ws_verify_params_t); + + pSignature = mbedtls_calloc( 1, signature_size ); + if ( pSignature == NULL) + { + ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_ecp_point_write_binary( grp, Q, MBEDTLS_ECP_PF_UNCOMPRESSED, + &temp_size, temp_buf, sizeof(temp_buf) ) ); + + CrysRet = CRYS_ECPKI_BuildPublKey(pDomain, temp_buf, temp_size, &verifyParams->pubKey); + if( CrysRet != CRYS_OK ) + { + ret = convert_CrysError_to_mbedtls_err( CrysRet ); + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( r, pSignature, ( ( grp->nbits + 7 ) / 8 ) ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( s, pSignature + ( ( grp->nbits + 7 ) / 8 ), ( ( grp->nbits + 7 ) / 8 ) ) ); + CrysRet = CRYS_ECDSA_Verify ( &verifyParams->verifyContext, + &verifyParams->pubKey, + hash_mode, + pSignature, + signature_size, + (uint8_t*)buf, + blen ); + if( CrysRet != CRYS_OK ) + { + ret = convert_CrysError_to_mbedtls_err( CrysRet ); + goto cleanup; + } + } + else + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + +cleanup: + + if( pHeap ) + { + mbedtls_zeroize( pHeap, heapSize ); + mbedtls_free( pHeap ); + } + + if( pSignature ) + { + mbedtls_zeroize( pSignature, signature_size ); + mbedtls_free( pSignature ); + + } + + return ret; +} +#endif /* MBEDTLS_ECDSA_VERIFY_ALT */ + +#if defined(MBEDTLS_ECDSA_GENKEY_ALT) +int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret = 0; + CRYSError_t CrysRet = CRYS_OK; + void* pHeap = NULL; + size_t heapSize = 0; + uint32_t key_size = 2*MAX_KEY_SIZE_IN_BYTES + 1; + const CRYS_ECPKI_Domain_t* pDomain = CRYS_ECPKI_GetEcDomain ( convert_mbedtls_grp_id_to_crys_domain_id( gid ) ); + mbedtls_rand_func_container cc_rand = { f_rng, p_rng }; + + + if ( pDomain ) + { + uint8_t temp_buf[ 2 * MAX_KEY_SIZE_IN_BYTES + 1 ] = {0}; + + cc_ecc_ws_keygen_params_t* kgParams = mbedtls_calloc( 1, sizeof(cc_ecc_ws_keygen_params_t) ); + if ( kgParams == NULL ) + return ( MBEDTLS_ERR_ECP_ALLOC_FAILED ); + + pHeap = kgParams; + heapSize = sizeof(cc_ecc_ws_keygen_params_t); + + CrysRet = CRYS_ECPKI_GenKeyPair( &cc_rand, convert_mbedtls_to_cc_rand, pDomain, + &kgParams->privKey, &kgParams->pubKey, + &kgParams->kgTempData, NULL ); + if ( CrysRet != CRYS_OK ) + { + ret = convert_CrysError_to_mbedtls_err( CrysRet ); + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ctx->grp, gid ) ); + + CrysRet = CRYS_ECPKI_ExportPublKey( &kgParams->pubKey, CRYS_EC_PointUncompressed, temp_buf, &key_size ); + if ( CrysRet != CRYS_OK ) + { + ret = convert_CrysError_to_mbedtls_err( CrysRet ); + goto cleanup; + } + + ret = mbedtls_ecp_point_read_binary( &ctx->grp, &ctx->Q, temp_buf, key_size ); + if ( ret != 0 ) + goto cleanup; + + memset ( temp_buf, 0 , sizeof(temp_buf) ); + + CrysRet = CRYS_COMMON_ConvertLswMswWordsToMsbLsbBytes( temp_buf, (ctx->grp.nbits+7)/8, + kgParams->privKey.PrivKeyDbBuff, + 4*((((ctx->grp.nbits+7)/8)+3)/4) ); + if ( CrysRet != CRYS_OK ) + { + ret = convert_CrysError_to_mbedtls_err( CrysRet ); + mbedtls_zeroize( temp_buf, sizeof(temp_buf) ); + goto cleanup; + } + + ret = mbedtls_mpi_read_binary( &ctx->d, temp_buf, (ctx->grp.nbits+7)/8 ); + mbedtls_zeroize( temp_buf, sizeof(temp_buf) ); + if ( ret != 0 ) + { + goto cleanup; + } + } + else + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + + +cleanup: + if ( pHeap ) + { + mbedtls_zeroize( pHeap, heapSize ); + mbedtls_free ( pHeap ); + } + return ( ret ); +} +#endif /* MBEDTLS_ECDSA_GENKEY_ALT */ diff --git a/features/mbedtls/targets/TARGET_CRYPTOCELL310/include/crys_common.h b/features/mbedtls/targets/TARGET_CRYPTOCELL310/include/crys_common.h new file mode 100644 index 0000000000..74c6302e63 --- /dev/null +++ b/features/mbedtls/targets/TARGET_CRYPTOCELL310/include/crys_common.h @@ -0,0 +1,371 @@ +/************************************************************************************** +* Copyright (c) 2016-2017, ARM Limited or its affiliates. All rights reserved * +* * +* This file and the related binary are licensed under the following license: * +* * +* ARM Object Code and Header Files License, v1.0 Redistribution. * +* * +* Redistribution and use of object code, header files, and documentation, without * +* modification, are permitted provided that the following conditions are met: * +* * +* 1) Redistributions must reproduce the above copyright notice and the * +* following disclaimer in the documentation and/or other materials * +* provided with the distribution. * +* * +* 2) Unless to the extent explicitly permitted by law, no reverse * +* engineering, decompilation, or disassembly of is permitted. * +* * +* 3) Redistribution and use is permitted solely for the purpose of * +* developing or executing applications that are targeted for use * +* on an ARM-based product. * +* * +* DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "AS IS." ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT * +* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, * +* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * +* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * +* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * +* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * +* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +**************************************************************************************/ + + + + +#ifndef CRYS_COMMON_H +#define CRYS_COMMON_H + +#include "crys_common_error.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/************************ Defines ******************************/ + +#define CRYS_AES_SECRET_KEY_SIZE_IN_WORDS 4 + +/* the ROT13 definition - relevant only on SW low level engines compiled in the ROT mode */ +#define CRYS_COMMON_ROT_13_OFFSET 13 + + + +/************************ Enums ********************************/ + +/************************ Typedefs ****************************/ + +/************************ Structs *****************************/ + +/************************ Public Variables *********************/ + +/************************ Public Functions *********************/ + + + +/*********************************************************************** + ** + * @brief This function executes a reverse bytes copying from one buffer to another buffer. + * + * Overlapping of buffers is not allowed, excluding the case, when destination and source + * buffers are the same. + * Example of a 5 byte buffer: + * + * dst_ptr[4] = src_ptr[0] + * dst_ptr[3] = src_ptr[1] + * dst_ptr[2] = src_ptr[2] + * dst_ptr[1] = src_ptr[3] + * dst_ptr[0] = src_ptr[4] + * + * @param[in] dst_ptr - The pointer to destination buffer. + * @param[in] src_ptr - The pointer to source buffer. + * @param[in] size - The size in bytes. + * + */ + CRYSError_t CRYS_COMMON_ReverseMemcpy( uint8_t *dst_ptr , uint8_t *src_ptr , uint32_t size ); + + +/*********************************************************************** + ** + * @brief This function converts aligned words array to bytes array/ + * + * 1. Assumed, that input buffer is aligned to 4-bytes word and + * bytes order is set according to machine endianness. + * 2. Output buffer receives data as bytes stream from LSB to MSB. + * For increasing performance on small buffers, the output data is given + * by rounded down pointer and alignment. + * 3. This implementation is given for both Big and Little endian machines. + * + * + * @param[in] in32_ptr - The pointer to aligned input buffer. + * @param[in] out32_ptr - The 32-bits pointer to output buffer (rounded down to 4 bytes) . + * @param[in] outAlignBits - The actual output data alignment; + * @param[in] sizeWords - The size in words (sizeWords >= 1). + * + * return - no return value. + */ + void CRYS_COMMON_AlignedWordsArrayToBytes( uint32_t *in32_ptr , uint32_t *out32_ptr , + uint32_t outAlignBits, uint32_t sizeWords ); + +/***********************************************************************/ + /** + * @brief This function converts in place words byffer to bytes buffer with + * reversed endianity of output array. + * + * The function can convert: + * - big endian bytes array to words array with little endian order + * of words and backward. + * + * Note: + * 1. Endianness of each word in words buffer should be set allways + * according to processor used. + * 2. Implementation is given for both big and little endianness of + * processor. + * + * @param[in] buf_ptr - The 32-bits pointer to input/output buffer. + * @param[in] sizeWords - The size in words (sizeWords > 0). + * + * @return - no return value. + */ +void CRYS_COMMON_InPlaceConvertBytesWordsAndArrayEndianness( + uint32_t *buf_ptr, + uint32_t sizeWords); + + +/***********************************************************************/ + /** + * @brief This function converts big endianness bytes array to aligned words + * array with words order according to little endian / + * + * 1. Assumed, that input bytes order is set according + * to big endianness: MS Byte is most left, i.e. order is from + * Msb to Lsb. + * 2. Output words array should set according to + * little endianness words order: LSWord is most left, i.e. order + * is from Lsw to Msw. Order bytes in each word - according to + * 3. Implementation is given for both big and little + * endianness of processor. + * + * @param[out] out32_ptr - The 32-bits pointer to output buffer. + * @param[in] sizeOutBuffBytes - The size in bytes of output buffer, must be + * aligned to 4 bytes and not less than sizeInBytes. + * @param[in] in8_ptr - The pointer to input buffer. + * @param[in] sizeInBytes - The size in bytes of input data(sizeBytes >= 1). + * + * @return CRYSError_t - On success CRYS_OK is returned, on failure a + * value MODULE_* as defined in . + */ +CRYSError_t CRYS_COMMON_ConvertMsbLsbBytesToLswMswWords( + uint32_t *out32_ptr, + uint32_t sizeOutBuffBytes, + const uint8_t *in8_ptr, + uint32_t sizeInBytes); + + +/***********************************************************************/ + /** + * @brief This function converts LE 32bit-words array to BE bytes array. + * + * Note: The function allows output full size of the data and also output + * without leading zeros, if the user gives appropriate exact output + * size < input size. + * + * Assuming: + * 1. Output bytes order is according to big endianness: + * MS Byte is most left, i.e. order is from Msb to Lsb. + * 2. Input array words order is set according to + * little endianness words order: LSWord is most left, i.e. order + * is from Lsw to Msw. Bytes order in each word - according to + * processor endianness. + * 3. Owerlapping of buffers is not allowed, besides in + * place operation and size aligned to full words. + * 4. Implementation is given for both big and little + * endianness of processor. + * + * @param[in] out8_ptr - The bytes pointer to the output buffer. + * @param[in] sizeOutBuffBytes - The size of the data in bytes to output; must + * be not less, than sizeInBytes. + * @param[out] in32_ptr - The pointer to the input buffer. + * @param[in] sizeInpBytes - The size of the input data in bytes. The size must + * be > 0 and aligned to 4 bytes. + * + * @return CRYSError_t - On success CRYS_OK is returned, on failure a + * value MODULE_* as defined in . + */ +CRYSError_t CRYS_COMMON_ConvertLswMswWordsToMsbLsbBytes( + uint8_t *out8_ptr, + uint32_t sizeOutBytes, + uint32_t *in32_ptr, + uint32_t sizeInpBytes); + + +/***********************************************************************/ +/** + * @brief VOS_GetGlobalData get the global random key hidden inside the function + * the global data implemented for now are random key buffer and AES secret key buffer + * + * When no_rtos is declared then we allow a global data. The random key/AES secret key are hidden as static inside the function + * + * + * @param[in] Globalid select the buffer + * @param[in] GlobalDataSizeWords - the global data buffer size needed in words - this value must be a predetermined value + * @param[out] GlobalData_ptr - Pointer to the global buffer returned. The buffer must be at least GlobalDataSizeWords size + * + * @return CRYSError_t - On success CRYS_OK is returned, on failure an Error as defined in VOS_error + */ +CRYSError_t CRYS_COMMON_GetGlobalData(uint16_t Globalid, uint32_t *GlobalData_ptr, uint16_t GlobalDataSizeWords); + + +/***********************************************************************/ +/** +* @brief CRYS_COMMON_StoreGlobalData store the global random key into the global buffer hidden inside the function +* the global data implemented for now are random key buffer and AES secret key buffer +* +* +* @param[in] Globalid - random key / AES secret key +* @param[in] GlobalDataSizeWords - the global data buffer size needed in words - this value must be a predetermined value +* @param[in] GlobalData_ptr - Pointer to the global buffer to be saved. The buffer must be at least GlobalDataSizeWords size +* +* Return Value: +*/ +CRYSError_t CRYS_COMMON_StoreGlobalData(uint16_t Globalid, uint32_t *GlobalData_ptr, uint16_t GlobalDataSizeWords); + + +/***********************************************************************/ +/** + * @brief The CRYS_COMMON_CutAndSaveEndOfLliData() function saves the data from end of source + * memory, pointed by LLI table, to destination memory, and decreases the LLI table accordingly. + * + * The function executes the following major steps: + * + * 1. Starts copy bytes from last byte of last chunk of source LLI table into + * last byte of destination memory. + * 2. Continues copy bytes in reverse order while not completes copying of all amount of data. + * 3. If last chunk of source or destination data is not enough, the function crosses + * to next chunk of LLI table. + * 4. Decreases the Data size of last updated LLI entry and sets the LAST bit. + * 5. Exits with the OK code. + * + * + * @param[in] SrcLliTab_ptr - The pointer to the LLI table, containing pointers and sizes of + * chunks of source data. The table need to be aligned and placed + * in SEP SRAM. + * @param[in] SrcLliTabSize_ptr - The pointer to buffer, containing th size of the LLI table in words. + * @param[in] Dest_ptr - The destination address for copying the data. + * @param[in] DataSize - The count of bytes to copy. + * + * @return CRYSError_t - On success CRYS_OK is returned, + * - CRYS_COMMON_ERROR_IN_SAVING_LLI_DATA_ERROR + * + * NOTE: 1. Because the function is intended for internal using, it is presumed that all input parameters + * are valid. + * 2. Assumed, that copied source not may to take more than two last chunks of source memory. + */ + CRYSError_t CRYS_COMMON_CutAndSaveEndOfLliData( + uint32_t *SrcLliTab_ptr, + uint32_t *SrcLliTabSize_ptr, + uint8_t *Dst_ptr, + uint32_t DataSize); + +/***********************************************************************/ +/** + * @brief The CRYS_COMMON_CutAndSaveBeginOfLliData() function saves the data from beginning of source + * memory, pointed by LLI table, to destination memory, and decreases the LLI table accordingly. + * + * The function executes the following major steps: + * + * 1. Starts copy bytes from first byte of first chunk of source LLI table into + * destination memory. + * 2. If first chunk of source is not enough, the function crosses + * to next chunk of LLI table. + * 3. Updates LLI table pointer and size according to copied amount of data. + * 5. Exits with the OK code. + * + * @param[in/out] SrcLliTab_ptr_ptr - The pointer to pointer to the LLI table, containing pointers and + * sizes of the chunks of source data. The table need to be aligned and + * placed in SRAM. + * @param[in/out] SrcLliTabSize_ptr - The pointer to buffer, containing th size of the LLI table in words. + * @param[in] Dest_ptr - The destination address for copying the data. + * @param[in] DataSize - The count of bytes to copy. + * + * @return - no return value. + * + * NOTE: 1. Because the function is intended for internal using, it is presumed that all input parameters + * are valid. + * 2. Assumed, that copied source not may to take more than two first chunks of source memory. + */ + void CRYS_COMMON_CutAndSaveBeginOfLliData( + uint32_t **SrcLliTab_ptr_ptr, + uint32_t *SrcLliTabSize_ptr, + uint8_t *Dst_ptr, + uint32_t DataSize); + +/***********************************************************************/ + /** + * @brief This function converts 32-bit words array with little endian + * order of words to bytes array with little endian (LE) order of bytes. + * + * Assuming: no buffers overlapping, in/out pointers and sizes not equall to NULL, + the buffer size must be not less, than input data size. + * + * @param[out] out8Le - The bytes pointer to output buffer. + * @param[in] in32Le - The pointer to input 32-bit words buffer. + * @param[in] sizeInWords - The size in words of input data (sizeWords >= 0). + * + * @return CRYSError_t - On success CRYS_OK is returned, on failure a + * value MODULE_* as defined in . + */ +void CRYS_COMMON_ConvertLswMswWordsToLsbMsbBytes( + uint8_t *out8Le, + const uint32_t *in32Le, + size_t sizeInWords); + + +/***********************************************************************/ +/** + * @brief This function converts bytes array with little endian (LE) order of + * bytes to 32-bit words array with little endian order of words and bytes. + * + * Assuming: No owerlapping of buffers; in/out pointers and sizes are not equall to NULL. + * If is in-place conversion, then the size must be multiple of 4 bytes. + * @param[out] out32Le - The 32-bits pointer to output buffer. The buffer size must be + * not less, than input data size. + * @param[in] in8Le - The pointer to input buffer. + * @param[in] sizeInBytes - The size in bytes of input data(sizeBytes > 0). + * + * @return CRYSError_t - On success CRYS_OK is returned, on failure a + * value MODULE_* as defined in . + */ +void CRYS_COMMON_ConvertLsbMsbBytesToLswMswWords( + uint32_t *out32Le, + const uint8_t *in8Le, + size_t sizeInBytes); + + +/** + * The function compares value of byte vector to null. + * + * @author reuvenl (6/20/2016) + * + * @param vect - a pointer to bytes vector. + * @param sizeBytes - size of the vector. + * + * @return uint32_t - if vector's value iz zero, then returns 1, else - 0; + */ +uint32_t CRYS_COMMON_CheckIsVectorZero(uint8_t *vect, uint32_t sizeBytes); + + + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/features/mbedtls/targets/TARGET_CRYPTOCELL310/include/crys_common_error.h b/features/mbedtls/targets/TARGET_CRYPTOCELL310/include/crys_common_error.h new file mode 100644 index 0000000000..03c73c54d6 --- /dev/null +++ b/features/mbedtls/targets/TARGET_CRYPTOCELL310/include/crys_common_error.h @@ -0,0 +1,95 @@ +/************************************************************************************** +* Copyright (c) 2016-2017, ARM Limited or its affiliates. All rights reserved * +* * +* This file and the related binary are licensed under the following license: * +* * +* ARM Object Code and Header Files License, v1.0 Redistribution. * +* * +* Redistribution and use of object code, header files, and documentation, without * +* modification, are permitted provided that the following conditions are met: * +* * +* 1) Redistributions must reproduce the above copyright notice and the * +* following disclaimer in the documentation and/or other materials * +* provided with the distribution. * +* * +* 2) Unless to the extent explicitly permitted by law, no reverse * +* engineering, decompilation, or disassembly of is permitted. * +* * +* 3) Redistribution and use is permitted solely for the purpose of * +* developing or executing applications that are targeted for use * +* on an ARM-based product. * +* * +* DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "AS IS." ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT * +* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, * +* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * +* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * +* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * +* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * +* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +**************************************************************************************/ + + + + #ifndef CRYS_COMMON_ERROR_H +#define CRYS_COMMON_ERROR_H + +#include "crys_error.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/************************ Defines ******************************/ + +/* CRYS COMMON module errors. Base address - 0x00F00D00 */ + +#define CRYS_COMMON_INIT_HW_SEM_CREATION_FAILURE (CRYS_COMMON_MODULE_ERROR_BASE + 0x0UL) +#define CRYS_COMMON_DATA_IN_POINTER_INVALID_ERROR (CRYS_COMMON_MODULE_ERROR_BASE + 0x4UL) +#define CRYS_COMMON_DATA_SIZE_ILLEGAL (CRYS_COMMON_MODULE_ERROR_BASE + 0x5UL) +#define CRYS_COMMON_DATA_OUT_DATA_IN_OVERLAP_ERROR (CRYS_COMMON_MODULE_ERROR_BASE + 0x6UL) +#define CRYS_COMMON_DATA_OUT_POINTER_INVALID_ERROR (CRYS_COMMON_MODULE_ERROR_BASE + 0x7UL) +#define CRYS_COMMON_OUTPUT_BUFF_SIZE_ILLEGAL (CRYS_COMMON_MODULE_ERROR_BASE + 0x9UL) + +#define CRYS_COMMON_TST_UTIL_CHUNK_SIZE_SMALL_ERROR (CRYS_COMMON_MODULE_ERROR_BASE + 0x10UL) +#define CRYS_COMMON_ERROR_IN_SAVING_LLI_DATA_ERROR (CRYS_COMMON_MODULE_ERROR_BASE + 0x11UL) + + +#define CRYS_COMMON_TST_UTIL_LLI_ENTRY_SIZE_TOO_SMALL_ERROR (CRYS_COMMON_MODULE_ERROR_BASE + 0x12UL) +#define CRYS_COMMON_TST_CSI_DATA_SIZE_EXCEED_ERROR (CRYS_COMMON_MODULE_ERROR_BASE + 0x13UL) +#define CRYS_COMMON_TST_CSI_MODULE_ID_OUT_OF_RANGE (CRYS_COMMON_MODULE_ERROR_BASE + 0x14UL) +#define CRYS_COMMON_TST_CSI_MEMORY_MAPPING_ERROR (CRYS_COMMON_MODULE_ERROR_BASE + 0x15UL) + +#define CRYS_COMMON_TERM_HW_SEM_DELETE_FAILURE (CRYS_COMMON_MODULE_ERROR_BASE + 0x16UL) + +#define CRYS_COMMON_TST_UTIL_NOT_INTEGER_CHAR_ERROR (CRYS_COMMON_MODULE_ERROR_BASE + 0x17UL) +#define CRYS_COMMON_TST_UTIL_BUFFER_IS_SMALL_ERROR (CRYS_COMMON_MODULE_ERROR_BASE + 0x18UL) +#define CRYS_COMMON_POINTER_NOT_ALIGNED_ERROR (CRYS_COMMON_MODULE_ERROR_BASE + 0x19UL) + + +/************************ Enums ********************************/ + + +/************************ Typedefs ****************************/ + + +/************************ Structs ******************************/ + + +/************************ Public Variables **********************/ + + +/************************ Public Functions **********************/ + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/features/mbedtls/targets/TARGET_CRYPTOCELL310/include/crys_ecpki_domain.h b/features/mbedtls/targets/TARGET_CRYPTOCELL310/include/crys_ecpki_domain.h new file mode 100644 index 0000000000..8475d522e5 --- /dev/null +++ b/features/mbedtls/targets/TARGET_CRYPTOCELL310/include/crys_ecpki_domain.h @@ -0,0 +1,80 @@ +/************************************************************************************** +* Copyright (c) 2016-2017, ARM Limited or its affiliates. All rights reserved * +* * +* This file and the related binary are licensed under the following license: * +* * +* ARM Object Code and Header Files License, v1.0 Redistribution. * +* * +* Redistribution and use of object code, header files, and documentation, without * +* modification, are permitted provided that the following conditions are met: * +* * +* 1) Redistributions must reproduce the above copyright notice and the * +* following disclaimer in the documentation and/or other materials * +* provided with the distribution. * +* * +* 2) Unless to the extent explicitly permitted by law, no reverse * +* engineering, decompilation, or disassembly of is permitted. * +* * +* 3) Redistribution and use is permitted solely for the purpose of * +* developing or executing applications that are targeted for use * +* on an ARM-based product. * +* * +* DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "AS IS." ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT * +* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, * +* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * +* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * +* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * +* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * +* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +**************************************************************************************/ + + + +#ifndef CRYS_ECPKI_DOMAIN_H +#define CRYS_ECPKI_DOMAIN_H + + +/*! +@file +@brief Defines the ecpki build domain API. +@defgroup crys_ecpki_domain CryptoCell ECC domain APIs +@{ +@ingroup cryptocell_ecpki +*/ + + +#include "crys_error.h" +#include "crys_ecpki_types.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + +/********************************************************************************** + * CRYS_ECPKI_GetEcDomain function * + **********************************************************************************/ + +/*! + * @brief The function returns a pointer to an ECDSA saved domain (one of the supported domains). + * + * @return Domain pointer on success. + * @return NULL on failure. + */ + +const CRYS_ECPKI_Domain_t *CRYS_ECPKI_GetEcDomain(CRYS_ECPKI_DomainID_t domainId /*!< [in] Index of one of the domain Id (must be one of the supported domains). */); + +#ifdef __cplusplus +} +#endif +/** +@} +*/ +#endif diff --git a/features/mbedtls/targets/TARGET_CRYPTOCELL310/include/ssi_pal_compiler.h b/features/mbedtls/targets/TARGET_CRYPTOCELL310/include/ssi_pal_compiler.h new file mode 100644 index 0000000000..3347adce35 --- /dev/null +++ b/features/mbedtls/targets/TARGET_CRYPTOCELL310/include/ssi_pal_compiler.h @@ -0,0 +1,147 @@ +/************************************************************************************** +* Copyright (c) 2016-2017, ARM Limited or its affiliates. All rights reserved * +* * +* This file and the related binary are licensed under the following license: * +* * +* ARM Object Code and Header Files License, v1.0 Redistribution. * +* * +* Redistribution and use of object code, header files, and documentation, without * +* modification, are permitted provided that the following conditions are met: * +* * +* 1) Redistributions must reproduce the above copyright notice and the * +* following disclaimer in the documentation and/or other materials * +* provided with the distribution. * +* * +* 2) Unless to the extent explicitly permitted by law, no reverse * +* engineering, decompilation, or disassembly of is permitted. * +* * +* 3) Redistribution and use is permitted solely for the purpose of * +* developing or executing applications that are targeted for use * +* on an ARM-based product. * +* * +* DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "AS IS." ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT * +* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, * +* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * +* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * +* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * +* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * +* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +**************************************************************************************/ + + +#ifndef __SSI_PAL_COMPILER_H__ +#define __SSI_PAL_COMPILER_H__ + +/*! +@file +@brief This file contains compiler related definitions. +@defgroup ssi_pal_compiler CryptoCell PAL platform dependant compiler specific definitions +@{ +@ingroup ssi_pal + +*/ + +#ifdef __GNUC__ + +/************************ Defines ******************************/ + +/*! Associate a symbol with a link section. */ +#define SASI_PAL_COMPILER_SECTION(sectionName) __attribute__((section(sectionName))) + +/*! Mark symbol as used, i.e., prevent garbage collector from dropping it. */ +#define SASI_PAL_COMPILER_KEEP_SYMBOL __attribute__((used)) + +/*! Make given data item aligned (alignment in bytes). */ +#define SASI_PAL_COMPILER_ALIGN(alignement) __attribute__((aligned(alignement))) + +/*! Mark function that never returns. */ +#define SASI_PAL_COMPILER_FUNC_NEVER_RETURNS __attribute__((noreturn)) + +/*! Prevent function from being inlined */ +#define SASI_PAL_COMPILER_FUNC_DONT_INLINE __attribute__((noinline)) + +/*! Given data type may cast (alias) another data type pointer. */ +/* (this is used for "superclass" struct casting) */ +#define SASI_PAL_COMPILER_TYPE_MAY_ALIAS __attribute__((__may_alias__)) + +/*! Get sizeof for a structure type member. */ +#define SASI_PAL_COMPILER_SIZEOF_STRUCT_MEMBER(type_name, member_name) \ + sizeof(((type_name *)0)->member_name) + +/*! Assertion. */ +#define SASI_ASSERT_CONCAT_(a, b) a##b +#define SASI_ASSERT_CONCAT(a, b) SASI_ASSERT_CONCAT_(a, b) +#define SASI_PAL_COMPILER_ASSERT(cond, message) \ + enum { SASI_ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(cond)) } + +#elif defined(__ARM_DSM__) || defined(__CC_ARM) +#define inline +/*! Associate a symbol with a link section. */ +#define SASI_PAL_COMPILER_SECTION(sectionName) __attribute__((section(sectionName))) + +/*! Mark symbol as used, i.e., prevent garbage collector from dropping it. */ +#define SASI_PAL_COMPILER_KEEP_SYMBOL __attribute__((used)) + +/*! Make given data item aligned (alignment in bytes). */ +#define SASI_PAL_COMPILER_ALIGN(alignement) __attribute__((aligned(alignement))) + +/*! Mark function that never returns. */ +#define SASI_PAL_COMPILER_FUNC_NEVER_RETURNS __attribute__((noreturn)) + +/*! Prevent function from being inlined. */ +#define SASI_PAL_COMPILER_FUNC_DONT_INLINE __attribute__((noinline)) + +/*! Given data type may cast (alias) another data type pointer. */ +/* (this is used for "superclass" struct casting) */ +#define SASI_PAL_COMPILER_TYPE_MAY_ALIAS __attribute__((__may_alias__)) + +/*! Get sizeof for a structure type member. */ +#define SASI_PAL_COMPILER_SIZEOF_STRUCT_MEMBER(type_name, member_name) \ + sizeof(((type_name *)0)->member_name) + +/*! Assertion. */ +#define SASI_ASSERT_CONCAT_(a, b) a##b +#define SASI_ASSERT_CONCAT(a, b) SASI_ASSERT_CONCAT_(a, b) +#define SASI_PAL_COMPILER_ASSERT(cond, message) \ + enum { SASI_ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(cond)) } +#elif defined(__ARM_DS__) +#define inline +/*! Associate a symbol with a link section. */ +#define SASI_PAL_COMPILER_SECTION(sectionName) __attribute__((section(sectionName))) + +/*! Mark symbol as used, i.e., prevent garbage collector from dropping it. */ +#define SASI_PAL_COMPILER_KEEP_SYMBOL __attribute__((used)) + +/*! Make given data item aligned (alignment in bytes). */ +#define SASI_PAL_COMPILER_ALIGN(alignement) __attribute__((aligned(alignement))) + +/*! Mark function that never returns. */ +#define SASI_PAL_COMPILER_FUNC_NEVER_RETURNS __attribute__((noreturn)) + +/*! Prevent function from being inlined. */ +#define SASI_PAL_COMPILER_FUNC_DONT_INLINE __attribute__((noinline)) + +/*! Given data type may cast (alias) another data type pointer. */ +/* (this is used for "superclass" struct casting) */ +#define SASI_PAL_COMPILER_TYPE_MAY_ALIAS + +/*! Get sizeof for a structure type member. */ +#define SASI_PAL_COMPILER_SIZEOF_STRUCT_MEMBER(type_name, member_name) \ + sizeof(((type_name *)0)->member_name) + +/*! Assertion. */ +#define SASI_ASSERT_CONCAT_(a, b) a##b +#define SASI_ASSERT_CONCAT(a, b) SASI_ASSERT_CONCAT_(a, b) +#define SASI_PAL_COMPILER_ASSERT(cond, message) \ + enum { SASI_ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(cond)) } +#else +#error Unsupported compiler. +#endif +/** +@} + */ +#endif /*__SSI_PAL_COMPILER_H__*/ diff --git a/features/mbedtls/targets/TARGET_CRYPTOCELL310/include/ssi_pka_hw_plat_defs.h b/features/mbedtls/targets/TARGET_CRYPTOCELL310/include/ssi_pka_hw_plat_defs.h new file mode 100644 index 0000000000..c205919f5c --- /dev/null +++ b/features/mbedtls/targets/TARGET_CRYPTOCELL310/include/ssi_pka_hw_plat_defs.h @@ -0,0 +1,77 @@ +/************************************************************************************** +* Copyright (c) 2016-2017, ARM Limited or its affiliates. All rights reserved * +* * +* This file and the related binary are licensed under the following license: * +* * +* ARM Object Code and Header Files License, v1.0 Redistribution. * +* * +* Redistribution and use of object code, header files, and documentation, without * +* modification, are permitted provided that the following conditions are met: * +* * +* 1) Redistributions must reproduce the above copyright notice and the * +* following disclaimer in the documentation and/or other materials * +* provided with the distribution. * +* * +* 2) Unless to the extent explicitly permitted by law, no reverse * +* engineering, decompilation, or disassembly of is permitted. * +* * +* 3) Redistribution and use is permitted solely for the purpose of * +* developing or executing applications that are targeted for use * +* on an ARM-based product. * +* * +* DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * +* CONTRIBUTORS "AS IS." ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT * +* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, * +* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * +* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * +* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * +* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * +* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +**************************************************************************************/ + + + +#ifndef PKA_HW_PLAT_DEFS_H +#define PKA_HW_PLAT_DEFS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/*! +@file +@brief Contains the enums and definitions that are used in the PKA code (definitions that are platform dependent). +@defgroup ssi_pka_hw_plat_defs CryptoCell PKA specific types and definitions +@{ +@ingroup cryptocell_pka + +*/ + +/*! Size of PKA engine word.*/ +#define SASI_PKA_WORD_SIZE_IN_BITS 64 +/*! Maximal supported modulus size in bits. */ +#define CRYS_SRP_MAX_MODULUS_SIZE_IN_BITS 3072 +/*! Maximal supported modulus size in RSA in bits. */ +#define CRYS_RSA_MAX_VALID_KEY_SIZE_VALUE_IN_BITS 2048 +/*! Maximal supported key generation size in RSA in bits. */ +#define CRYS_RSA_MAX_KEY_GENERATION_HW_SIZE_BITS 2048 + +/*! PKA operations maximal count of extra bits. */ +#define PKA_EXTRA_BITS 8 +/*! PKA operations number of memory registers. */ +#define PKA_MAX_COUNT_OF_PHYS_MEM_REGS 32 + + +#ifdef __cplusplus +} +#endif +/** +@} + */ +#endif //PKA_HW_PLAT_DEFS_H + + diff --git a/features/mbedtls/targets/TARGET_CRYPTOCELL310/mbedtls_device.h b/features/mbedtls/targets/TARGET_CRYPTOCELL310/mbedtls_device.h index 4034356243..a8c66f9c02 100644 --- a/features/mbedtls/targets/TARGET_CRYPTOCELL310/mbedtls_device.h +++ b/features/mbedtls/targets/TARGET_CRYPTOCELL310/mbedtls_device.h @@ -26,5 +26,10 @@ #define MBEDTLS_SHA1_ALT #define MBEDTLS_SHA256_ALT #define MBEDTLS_CCM_ALT +#define MBEDTLS_ECDSA_VERIFY_ALT +#define MBEDTLS_ECDSA_SIGN_ALT +#define MBEDTLS_ECDSA_GENKEY_ALT +#define MBEDTLS_ECDH_GEN_PUBLIC_ALT +#define MBEDTLS_ECDH_COMPUTE_SHARED_ALT #endif //__MBEDTLS_DEVICE__