From 0fe7a2d4fff9dc12418eef835bac61d086cb573a Mon Sep 17 00:00:00 2001 From: Tom St Denis Date: Sun, 8 Jun 2003 20:09:10 +0000 Subject: [PATCH] added libtommath-0.20 --- bn.pdf | Bin 233008 -> 232850 bytes bn.tex | 2 +- bn_mp_exptmod_fast.c | 1 - changes.txt | 4 + etc/2kprime.1 | 3 +- etc/2kprime.c | 2 +- makefile | 5 +- pics/expt_state.sxd | Bin 6869 -> 0 bytes pics/expt_state.tif | Bin 87542 -> 0 bytes pics/makefile | 23 - pics/sliding_window.TIF | Bin 53880 -> 0 bytes pics/sliding_window.sxd | Bin 6787 -> 0 bytes poster.pdf | Bin 37651 -> 37650 bytes pre_gen/mpi.c | 1 - tdcal.pdf | Bin 0 -> 56671 bytes tommath.out | 143 - tommath.src | 4675 ---------------------- tommath.tex | 8141 --------------------------------------- 18 files changed, 10 insertions(+), 12990 deletions(-) delete mode 100644 pics/expt_state.sxd delete mode 100644 pics/expt_state.tif delete mode 100644 pics/makefile delete mode 100644 pics/sliding_window.TIF delete mode 100644 pics/sliding_window.sxd create mode 100644 tdcal.pdf delete mode 100644 tommath.out delete mode 100644 tommath.src delete mode 100644 tommath.tex diff --git a/bn.pdf b/bn.pdf index 37866c8efa910ba2b305ce0b53717a137931a3b0..bdbc819b73274308c2aa503366b86f27e2a46ee2 100644 GIT binary patch delta 84008 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 QC!99!TGrd`;e1^G0UZD+9smFU delta 84023 zcmY(KQ*bT{u&iU-wv!dxHdbugPFDEGwr$(CZQHh;v+q4m=dEk1tLAN{s_W~7OoX~D zgg7-oWgDW@{K64#lMx&v&a6zr4EmB!3E;W3)RC~o*tE~E) zvUL{!+*_cu;k{nLi^u`%tWlmWesqm7!_J(&Kh9cyF-FRgRE-F^#e;OkuZ4br3<^*_NJ1G}zdu&KQC`4G90?W_NfA}i5*^VHBT>3;JP;WpZ~_gL zF;klkkw`IGSb!6nd7U}_``$blQkT_al4C6~IvJ{ka-Z1@1?n7yDOgOoKb$zr+7DPa zZc+Caa?44i7d6uqq2d%^Vv*|`LJWL3Y?%s(wo2qjkmKDf3jJReS#=A@7x zEg)Zsn0}OKugfYQTF(L{2|O=}6+)C$10?HGM2CGB41X&Nyk#_H&q05;^~BBv0Y>m| z7L3~Hx3)_PkGk`(^5S}&1*wp3(YAOmdS}G`jU>BN*EW8XGPb*^d zG>}in?|?ZC%mC#&b$S3gLJ#CjQb~wah}o<*aTeHyCO*xU+1Crg-JQfTwmXm%bM4WB zV%7f;Dl7Y~{C66zfBql&6Y{(fUW~zDNPCTnR02}z$qqdJ+$A?o@nH}nv@~}2c96^A z&$fg$GtC083=b^;bMvBY(%SiJmQCl^th|I$9g?>90Mnl5AN!SuYJU9A+yU|85atMU zXcM)+tzO~zJr|+dG+a4JC`{sI^xz20@P(J-Nn%FmhyLmo7UBM-&AacNm6+bY_2L4F zX+#+i8`1v3j&CzqoYu+;+}LY(lpqguBjR+(nHqP-L@aLrmVW$k8dsb}oV&@qU?_#H z`$jwdaOS(ktzPPtZDMS{yU+a+c%Qk53IZz^=-Fs4 zTdI}fSa(#2%eFb$&HZ3)YUxXw0h;z4KCkMfV|1szu$TT7#DfuC6{&Cg{q+;vVczVY z8DR&&P?}-tMJWgDJV~|p7rO9D`_^WcPH^6ISFh+uG#FbMONZy&W6^)C{4#*6r+R-K zA6#!sXvJt2Mdc@sZ~eIV2$)9Vitudj&^cXq^>X+8=}921#F=W?q}yND6ac8NdEb>k zC;j9vdQJ1_$OXeMYrC${u{6wAA#{ISP2B;SrDaT(`NXO`17COI?(VKOM}ltze&k zo~&0^LSRIAA+P=vLvX$OMEPQ_n*Nr-C_K+|y%B8}tYNQNCcdJt=CW|#(^)Y$O6~zZ z1CKP!!v@dh|GkFGQLgV#)Gpv*R%;Tx&!-QpsPz{MPSUQ~b?P0(B=SAJ{Yz}T46J(j z!Q@MZN4}kOrl7wyW*Ccj`&5~%rI@6-G1-0o(}m=|7nd+OeWQD(;US}b^zL>yN_RZw zHC&%HkpwY&oSdJIZfo+o?B19H@^lG+(e5{m|2S0+vz%KDy0Bf}lOuIURSYGdRREtf zj?!8gQ3EtwwOuSBsP=4T2F!$8*{fBWz#b|DQe4|(W%5y1I&ONgL;_d`>m$P$IW?6z@_m$vn}G=KszqmKx)CUg}U94Y~~BBMAA zfVhw7I7|aB9esSZvbU#^^~fIv32lSQT?eZ&w|>L< zCj4Y~4?!$L^mJkQ#~9rN~CSU7Dn&z?TtgRhy`dw~BhG%z&;asmk&6!zpB zC5wTdpsAgSvx}3dp)JgRDm5P(*cC!VK}AzqIu#EF*b?@CHLZx85?ktg1~6u8DGYEi z2%zdmPf_f6T43}&mJK~GIlHkV^m|w87v=}DQGlh1D@N@Gh>snEo!!lX=;`xTAL3V4 zW?=@+$jlUy4{?hZD6f!o4iw#!F>eU|&InRtJ>7o`n8>|MUk!sNjO7U#sEM2($T^Jk zLVxk-2&_&xwO??v_X!}a1EdCt8OAa;1pxb^djQe67K$k$;yE>sM(l%W3a*eBw1EAo zcB&U5^^YOqVI2G7N{Rf|zYv%m++~Jj4MuelRg-6*C0R=3TN^&t^y6j@UfTf4MYjX0 zEDr4^AG^^!cn=k!9V1lBE6MH?q?|Mdw^~O%g7Uz41Fk~incJO$cfGxO>6(Fm23*^m zLw%5fSgqq79K6v9UT0{x{~!Z5UxMN9?!vKMf;oK;(z>Wr<^5WKaV%A2FXxKC{cNyc zJ&cNc0gCIJKNON7t+3#nJnb+Lmzc)-!QXg!2+E8jd+Cwq8Z8ORDCf-sK9IdAEQrT@ z!!fl4FVgcelYJ;GFy74r%oP7o0M262a-lPn-|Y_qPgFc8$^@3p1Kbq8)AP_-bD%fS zuFV5Zmfkb-R!J(uN#~Xzj=l&fV+k|1!DxO@h4xOrcs>La$OM}5V4tcTU6_M8`C~yn zUF-P?1$@g86aQPy_?@}7o|nn;3HqBcO8B;V{|=hZPxm8ucJk*}unfBrAb_NW@dYV- z$=};@bv4)F1|VvpKSB&zY5oPxcg6n^w9p+DxT{6|gcOFn{LkmL{{Sg$+r~%w1PEXL zMhx1xdjtJlcAo=Gg=GhR>OVX({=6pBP(V1o8l3<$It$wWu{&GtADlgX%r(SuQ$wI9 z(u6+qni?4yeV?UWUK$1Q5yWe}8vnsqI`w~N zM}Cq2%tM{5Jc<1S3e`B-idD4U-%~Mjf_OnD1uY=3HTIhcUv0_W_QCtLVY1#{?WYz_ z?FeK+MB*MyA@T)4QwS8cN6C8S@vaMzHvVKEYE(rB`&!X(y`EnVbAR}u+53@38#y#z9y@aokmRJ9fVj=qvR;XhncmH&OP*N^a7a=x=$dAM1_5_UgfHj zE92ojKnM*nFj=_DAwfqtbrUXksC%iOddON-$#{tL;n;Q)EHmvD&Q1*!hI&wUNxz5s zJN{_V9fkm0X*iD)em5|4xkZ)JM8W*qc*-J}-cb`&940Fsd5vV26yhO9)IPekD1TT5 zwwlO7OyL^|erJ`Em;(HxK{?8|i&gJgV=Cc_xu&OgN23JI=fz|Zdgk?jYSE$ zta(Je?S#j12(cAe@Q8DwhV7gnvY;9KfhUMX)QkXZ5=QA$`;sSjr1v4J_zU%2-c89Z zwm8|ZO!tIFP8XtB3$?79+tTjhZ=SP&m4cI&6lV&FOxi$d8%$MV z)Si9X=5>onxfcNUo1gM(#&r;V@`;I&)#fc@puADy(%ElA4wkeObTo;(iMPgT<#KFR zai#%=KMtG~&EGjPD3$0IpbD}Nb(71fIZ$^aSMU;qiiAQjTfWH5*loTU9g=nX8uZh} zsbI)KiSBY7_>SXf4!C^e6;gWn97-VJQ@^PG?&Hd`KGQr{wYRdbQup8}rCX4G`4P}Y zVHaMwFS&hE*>$JxX9cJX5x!_&I|0>Tr>Ox@$=BDfDIT+Ti=V+`oTb)OTLNmoSMJCL zvkS9@+hTe-4ZU#I@(LSNw+}z@*kCJ{IQW^$NCd(muIx}Kidr=~-w(?@x|5lJO{yOn zLMcx+#V`8G!_9mS0X}xSM0)2YUk!OrOk`pEy1yV(E}G0994&c1@vU8C$`s!Gr8$5N zTK;FE{02)jxf~6siW!L7gh5 zJITp@VhK1?J$--Pjqjo^nTLvGDa=2eE?-Br-cHeOJy^<+&P-*VwhuX~dJBfJj3WTV zv|Lp&M)$>NMV!;|`5Y|f{YTCaF;f5@dWA>CEXU70OpI$!Qto)$50M$}O=Syu7ozr} zI_urS^73p4oB41*D=lJH#cFKD1=XO@wQt z>+n|C1qU`)jvTRbXj|P*G(H8k)xU~eaPiVhdv+LyU6x-@(8-Q?COuuiqSHdy#R((U zm9X%(_KWk4jBfV#p1Wj(pcw!=NNMBAcLmkVlFQIe4IACs?1j2 z=+v0Rx^zsA%C-1aXts5$y&X_J*edBCz%r29=;@t@4%C#OGo3D%G)L2xq!^#xx3IZc!SM^=Qe-WPKNjl%@S~ z$c;r!BHM;gIsZt@gA71hQ8xDM^Ann8U6Xs?D5c zHN$V2XlmZjseFtSDiA`5j zELgcQNg^=jTBuRo{-JfEc%-?Augxmg$fx{k_Z-SQ)4s0vZk6z^_2=|QzC07LI6l8F zzHH7Cws*BDu?p~2rJ8uzJx3yWE~vKm_2!zk5~i4H-x)N}E!;WXa@jBye@quB(A5s)c@rOWeF_Z z%o~~hmcC2yS2GawZI+SUI{HD`??%4~<{?dJWxH-4U?a{D)0NL2H8$ejk)wo*fR}~&BDK59*bb;HIT7Bqxc_!{3OAWv;*HBWrDHUA5b;P5cs?}_Gy}d5d zkg`~GTnhgN=WL4JfRanmt8jn>IcU6_0Zh6u%d;;(ssQF=4K#-a{a2sK>IveyGHzQ? ziTBP1+72zug?W{1;H#V`E45O#MQxig%qfeBq6F!L>=&DZ@)mqOGiU4Yb_B=-0VUJ4 zQh*L7^-2q$OY0n(%FpBJfBpjE!364B#1-UPzAv_k6{4!TO8Q=dEh%_K#&bVBI6895 z<5>?+K5b!_k=M#u?8B0of(fGD*Yvi9khaK0P@09qOPay>fRsg>jEUjp z^^ht};Und?J4f0VGh0eT*V3`>&kTOz6Tr7rQ~+$!B_gJqq(GLaU3)XmRLc03Y}X$K zdDR*!bvh-GsQ1(CH190(tl4dfZ7^V@`>0y9e=DJxch2#mrt^H_ktdU{40a@%9X2M2 zrdEE7sVg@HEov_lx1nPuZOJ`Xa+I;^+1i!Lviw`f>~)b$J$dSVI5Y~yGy;XxwgA~D zf&`WV>0UwjXkEgK9V=ngw=vXOvk&;g(HeG?j74oWv#wMn^hZz?dHy6kB@j9-Xr=pD zC$UtMbDhQs0fAPtr$~0TQHl~@;dGxm_`>sLg!FLZpL*b)wfgKAnz3TSB{&(hznDkU zhNY3$Y|XgeCf@bP9MzoBQt#6x=>X)zZzs`^UZBU#P+rEqR6{pQUGp+Fai21eZvH1CL=1wb z(BQ6HeY*^;?jho#Q4kZV-PB?n#JxBae*(UNjVkSQ_HWHN75r8{beK5jDjE5Dgm#(;v`OzngUbPR1#f6 zvc&Pah+XkdlA%T;nU&yja44@5CZ=xwp6XS8k zY^}@bZ<{}4H=_(~yL#Aa!F2KOiRQmRZC*MDD_v4PCgNIN(cR?e&}@Er%2Hc626bNV za7AAN=Y4mh*lf zD7#bKj@8Qqkq~vUXA434?H3VaP%LyYshQe2G{0Gk@s+yWztFU6!*Blh91|_!q(e67 z+G_K&l+BUB)|pXdv?ZPz)>=rv8HM;Jp2%C%!>|p8D}bh{ghraGZMo_U(UL^>b*9#x zoHpTBhK^>e9RS7<&1|TvnNcW4Ne z->eVo&nCt}-d}!!%pW9@WWxaE5=YTCJ&F0sM!;T>e#BYhT%3CrF>N<#7;OX?YKwsC z#9Ln3)LSpIh@N_TUf(kF^$r}laIA)cci-;OL!^_Il^bF!WijIV373>{hZF1QfY1Qr zx#Hwq1Mt2&q$ry>LVl|JHDepn@A`J(<~pr-h#Q==%(BR}URtt0PN zOUYbtiNk4YLFpg`cE7jw+AMfhu4|vQ=p@M80bIwJ#sktF5b&qGN2H?=dmglY@i1=U7rs}pkBcjG=i4jFeZ#_}gjxQ{WfoQ?7&~Ajw zfcQO1Z9Al%8*{~TwRR$@PuDKw5NU;5p2=NfpMk6mg#Jq%58`wRimrd7!%n_0)bVUz z6r)?4!Q`vg6AxEyZ{j(YlATPo$}TV0j8UK$J80J%VbXa__3*TA79e&9@Z8^Cqs;X8 z#j`7+=ls6W4i-^Cevp4PHSJl@=xsJ50JuAZtnHh4(N|riAkHhrUM)VEMnli=&3(4; zx8^V0OxFl!OI$+T)dYLc1X=98ZIP}aqn?XI+r6g)j120RK5fKP2KTfJ%VWI932|JP zF&m7GRG(k`0)7%L>b}7Wfpo(a-`~QDoF%lfO%a- zpnfaO_+sMRVb^x(=-lRlTk2oC81hXafe<9YqpEb26l(|jZeR{Og|0vv! zqf?I2MX{)CfyE9OK2wKaBrS-I#t?FSpEsC{(MMh;Nl=-Vl4%NayKlhP^B(4Sz#6LMaa4{x~ZQP}&yQFD~=KpC6PDBx$Xc=tWKdU90Son{W|j)XopQe>kVwa0^s z)|EgiR}=K#N$nffPTB(nY7q($6?*$iPFWA+G^Jj|cSvcjO**3kA?5Bh0kG60OBfU0 z@j7EUoJIk7MswZ?6{S3Hz!pg0%?wPWf-EQlt!f0eNG!SIJUDL6R1^_gB}zgX#ZeRlJq?BgidZqlZg zZe6Y==B?DZOP6wgl)IpAa!?ECwfF-$N#Jzd z;9ac8KKo7@IcP+?;Z>yz z{iW`c|8Y9A<-$I31MF4ii^4yqZUhjF59@gh`}z2F_N&w9=zBq5Yl3rS6t>dE0!c-c z(#3h3+hd8cx0HqvI}2PAW^<7}mj0BsC2@-+1eVQavifew^VpCqmviD0FU_|u-Bbfj zUdl%~Bcs<2>eAi@RcWWm2T~1VE{pNeLA49)u)}y$-TL^j1CUsVi(i<5iTR5zRKf}) zzppaSR-`fbC>h$2ZM%#topIrLVyus3^+V>%d8mcR6kJkXNVqn#+2Z7@%@VY15jptZ zhgK^%3SPWO?}&u*x(~|nl({(;N~Zxyv5Slhdz5i1%WoDlL^|Hb5!u3-wl9p8Hfc~Y zVh4$NyTN_7fUiXf!9b#7)I=_e(%BVSleJ8$dbb-kU@Z`e_S}L&P<^(R+O5bG&NaR< z?M8+OTGGM6EpOR2P@A5vtS_nEe|LH|Tu~6AvC__sY#~xfMC$dPMM2l(59lm0U(()y zQ>1$|tdiBZ5L&?>_ULwxhxyHPxcGhaE!T?MD(Z$R0LD1@#VjxUA(7Xqh|cT?BifDg zIwCMUv%DAjfGLpT8)Y;RD_?m!nnsE)t^{VGe`sY~wU1f*kUwO}*1nBnv~Wa6=!UcL z`gAfg*9s93XzbxJPBZAoc4@Gk!#MwF16dWCpP=yPcI7k`D<^)H(9-@JBFC_)TAP5m zaC<5|;8JGLP(@)Qj001`$c$TAkIW7?ov-H)2dg;fDO4BQ-0-G+)_@#M?KACn{h)2L z_}9oAhuh8ahD&n+---Rk6qfZfEQEETP0H;`mlKoS5$Bt)QdT#Pwr)IEv8lv0y3G75 z`ogDG-+DuZ<m870C`IxUAE%-poPr^|6IaFUDeG#nx#nF zyH0B+aY@0kY&C=lb*Jvihh}_zaC$wR^yvLwTeS)562#)eXRPzz+D^lOQ!6YY?{M}qEw=}bQ04AfeD116@)ro!(!Xn&1l@^(7qRc2H zKu5q*T4C13iqLvrzblCeyASAiWfg`WJV>lSXheiRTrTepw z;kZ}n-`_~&nr#U_?FESF{(QaKtEq38+M#YFaoUSZR}H2Xs4t8277d|8duR!i6Fe0g z9;M!ld<@R%55WfaXJ{vhAXHy_kAn*x)VA*!9YHAAZp0w{6$xrnGQkm4up5Gf2xlcKcMr^w&|-Nr*oO=*FEM9!+H^& zqr3bsh2_shWA zS5{B6%yBJ9GsmQ$J@@WF^B`9P0LsSKL$@Mtj;1s8;dX>zPB%6-H00ol!7(Tv7Tig0ibxEDw2JtB$i zpyr!WrHB&zp;?BG&z?`OU>ny=3IRT4r{>^9UBOs$PU*if87Jkx_s_!GfW+Q|tAFZ> zEkny7+udzW+?D~?N4UKtdvBH1i`|{;}XcO&)w5$;cc$x9AUV)f6PXQytCxFn1I6^`d`o)mpF#mcOWc7=pAn#;MQ% zMA#m+|L{p0kgOGP|L%PXnytpxh2(15C6 zoJx?^6@J@Rc7m=DCIU8(3QMl(VH&<={ICxqM?%|u5nU{q7LonSe2wN05eO*7U&0JYIAV%rpRO zWgWLZRSP&DdE8R4nQh;^(^PS+I50?^QzvG)f`AE8urs&@@+A7`P^R5an$`2S5 zlQh@LmIDSOR#8kbK-g@PXm24$pEqA{>_#Sk?t}VCOk3WWDDrL&9AKR48-VPH7e1{(lfJu{u^?wkf1#B zh`RS0P?+UH`{F?UNz>IqT6B5z*&L8S6A%ILYC~HoH~55ifb+SeM(}uDd@M>T;wv~) z=e}p63PPy=#7A3jSlW>Vga^mA3Kss&mTj}Z>&A^F9_BvfUSqT?!b7*~UeWw;?9x>f zWH$cnN!g0{C{8i&D?hDj$sJlJ2VPg_uw%E4TY=theAED{Mnluf;F1jH>6I1>@m-(Q zXUp`cB^1#WAR9}m-%YP|GhpWL0BNLg2HM`TwG}o$dR4d^A@YK(@3hvUm6Ir&XDkOz z1xVGT@)PAg%uXBTkR!yuXCuPyEVkSRgkXD*cjk+VmmHUwwWML8;e7F}D%dM?K-Ym?Nxk>CwTEqphAUva};;gq3vd6!E3dsSXZ`1l+hPMr=x(2YhmgVO;&+J~B=N$N(R4~UP0DpSKL z&w33%Ak;JIzUttLht>TqIg+AiW zSB6xGg-?Zyv0Qi0{rK%bB_aGQgA^;@G)zkt5Irx8<2qYOhrc#EGVMP4?N5d@Mafn8 z=KQ(8+-Y}fQ+2J&E|B#Tmf-LQj}R{fSZC*`jxNNs9?id9yd>4Rxee!O2G?5ieMtjf zhI!L0>)PS03j0Zrc&^sJ-e-JmjxL{=PxxgFW_)T)g3(gBk7!(bL0Xt)ImDs(C<^Hx zKx?q4-bS_(Spm#oG^cvV-d|oPi|XB=?FkRUF1mjHVE%451WsAbb!H}K75}JT3XxiWTtLdx z@;2GkyDoEMH$ZEjD0v!0DzMzprxQ4daIxm$n99W43t0})OYv>ROO}GgBqMSKXsG^S z0sp3Hw9sNW;)~!@y2ZfX>3C0P^s=1vPxhY1?az&_$!M)-vEI>V%*Oe&6EfyEfu=sc zgf7*4xt^RR@%MdhVgmjS1B?Rc?Cv(9O2>dTDdV&zv! z4^~%)-D!$;2(%xQ-UzxPeNhOWg5viyEQ$POuVbcFSMdpD=KZo72~8CNP&j22p1g>} z-P-at7B_t);dm^1Bwd++OyDwrbg8cWkQ=a|dhSSAMcE45ktqgjPBjV(1G)dP^_MQ! z$4hwD9jKMo2t{XN^$U$>hp&PBPKk{!A^4AhXgBRVXZAz?lQ3fb z1S}Euc3N)r*!{Jn6%>RI6mckN-oc5By^l^6R&WlOv7gW(a^O|gg-nZ6 zv(rI=Z5E-`v`(@CEePdh+w;AapAMt0k$VEsr4>@L+SkFC6RwWv>F1!SQ+ROKF7ik8 zYj~`fk7xXNbR?+dwfT;gdJ$eS)#vs%bEWdM7X4deLVDd4$ZHLP_X73nqTXBHYDHO z2OfTI*QUn45B&L9-nm|$;b`(RxZBAHA5MhTZ5CMy&*g=7o!kR6R*4u?0I#-18>CQt zU<~ZbA54B_1SZ|Z4&`sety!4qjLN-P{K^5C>DmSz`aP~=tTl^fC$~_VQXNHQP0t|0 zoAA5LV2yUi9`R-vyfcx-qKTrl4WoDmEnF!(g^e3Z|B{8lQrV{3H9S8k^zzU_2Q5nm z8cWB-kcjU%bXnlHPe2WK*i!U<^0r1%v~einS;w|fhNB}jDcg=Us4|rGb$-?%_wNH} zVT~En```eb7uB$#PQg?@xdI(>pC=sQXt2VpFOq6<8aoV|-U{07%xm=!tv2Sd3=5PN zIgMxoe>_-b+~`3DpKfwMSx7raC|qm<#q8YAkl-V(m8#^Hq+kni5A_SQx*iGG`}x;J zbbq@4FeA1>kzlQv3jJe8kgxOQk4y$&^q!X_hX#bImC(6T5oGR@7g70RTIK}3Lj7}I z{tk-`tj?|~f(m?;DzmGFHbc1w7Jb6g(w2lY#Y0AsvsOMy%fTAR>Tz9ukhjPXiJW=4 z8GUo_gA7SUvDY_o;d?-(B^+%{N{tI2+N53dqx(02#5RFdn{3BysF<2bSat%Syc%r{ ztQTMjU$K?FKkY$NCy9)`Th+CE&z3Fa=^xP=?Ym3H4R5=Kp~VXda4R-OWs0+qeGoEL zV7;Kyk;}O8WecAryRW9Wr~0Z&>U>sK3`2!rOyJ0s7lzryIKoviAo_yvSrVGlO|G7- zD9z(^APP0=aFa>bbu6ptcliQXzVoR0{w4p2>safSV5Jv2P?8>Px81!YU8+SV%v!H8 z0jZbak1N_w=nZ4AFva7<^5na?@luO4*cdI+!w+%0h}@`a)GU*%5)ojyy+XhYd?12g zwn%MTI-B2&-pqv?$k5@OF&6coUPe^2IB0xy4|o@zWJT-lP=7LL%%leBtxfg}F_KF` zAIjK9`ECkx)-vKXuc8#~H=`OlqgQVf*&IA!CT=fNEJsC* zG*TzMiXqSixD8$#OrXfDwac{G-O_AJB zA|n+*F-W+#JXWm0LJ|WkU}7qg>kPWg_rTx|gB1hH8jIYM-9b7o%hz1gFLAUxQ~49y z<5Euk4#OIF^`OSurek9@wrig{yf^FtI@2O3e{y zebGLvYX8>%a%-0m-dpu4+8B)=c?R-w^@aU8VIL{c0kub3^!l<5M6F`8XQDHfbiK>N z$0?AF%ww*;Nt)C493VyN>Sv)dV+|S<{tn0Df;k`khK5*+i1e~fb3ysb#%{=mCKgXc z6>a&4c4P`Z#Rm_NtoV*n$xh(r90yqHe{^(*RGHcQM|c%Rla9Ww`$m+KF0KdVE~}&@ zH&sBbYJM^Qu&pW^VVGb7h2C8z&db>jXcvqLNxAIeZzQy%Zm>h#BtBaj1ZFTAilz!Fc}gLc&hM}2?W ztJ#>&T(_7+RO(}I^ocVp3`J*kxz%6MjQlHf=>p=3f7?MxBYnI%nNhOmb&*Q>|mJ?Y`#3wtum&}ygEZqwLnbLs-54=7r09t%0n zWa7cxBd7zCl0MuBh^$Ol7Tmz z#@DhTy`zLhk&H4UQ$-Wtm3Tiu#p>+J9UN)TD+W)xInL}S+<+%en!`?V+qLnD2yB+U z_81iZe8hMaM^&ttUh*Io_Pybqqo$Y-x4YzWG=G$br}kzC+m7Iek1)x^ zhiw3P#MY8$V7KD$%0J z?S9?2O>Q`#!CPEOny3DVz!m4kp*MnTphF9Y@KVvAJvwfk zhyU{YiR%-ZS?TYg~k?d}+6XVFvIhN@2|bvarV|G^=aER$&>m`ENJLnQC9M4kIBFgI)y##_1d-VX3QZDfkErAF@ol zt*S-==#|3dfa7;s{!({fMrG1D9mDuuVLDbqaI3E;7tAg7K%oSKiMr z*slT^BY2=+%nXutULpL&FA&gyYeH%d7jPhif{LQt-@mC6+`v|_|EvFFo>f#*=Q4n? zT9>$iu^=HoJA&IiysTOug@DCD!N3SZ4O98VfCFIV#MQ)Qr2exjYo_L_0;8sGivcVB zpDD5$Fiz^lEHGZGgE;W>|7-gIt`h)%(M+*Mt?`gBobd#Oc<;qTgA+S-?=-mj?%&w( z#~htV#1CUlU%Q=+?J-|p&g8jouqG4oq2S0}kbKmCTmZ<+k z5KG%gZw6vfel`ABZG4;Op1$|&zCQZy!o$vAkf@@iLMn5qg$srJ>zm>Bfq}Zd(w+QFuOom0+ zm--+x8U`3dh|HWY4_CsL2wBFHerUGr^jQ_)0r^ts)&@jjL+q1t7Q{;u&n2Te?T*%48HyDFtH|Xrd!DEkJOac%Tk=t>3z7(+iN(f3xAxs3Pq8 zPY|RtJO~;Fu69WQ6s-D}mQ1Qpf8s=S3h}UCFJve?VzU0oTVh$>$9W0hS#_RjeU0Bd z4pUlAlqfIVKrul@zg~{=>|P*_xkHr1JF5D6k4|u~nR=DZzBRk0tgv1CZswmQ`jo@g z5zzDfY>}Rad|vznc2+2Kv-e1^kM7oR;dG3%;ad@EDarT%Qqwl)KKCva33tP)Cc>J9 z+A2NntIgHHH0*u6Y^RqzKEwOL9!B>wHcuJGn zC-Wa}V*oUGcptH^EL*fbqkq&JOxc#ba&MQr?nSyCx&M}>Pj!*&UYx!a6nW_yx=$EC zWq-N02wZUi&U#Lau8+?W;)KT6G>-F?83bN>6IwRT{yLn31k@()gXe3xDn4Y(wW_x& z5IV1ErQ`y>7y6Ugcp&-V6?&n3=ac`;&JczPWVdQw&@v&gd@fbuUJKkp_8+3uzRFPW z#;`}L>TrI`?FGMV$j*{}>3YPSiUCqhKAAE@V6@Qyw8@-alSdaBdDbUs5tgUZ@^|;} z9f5p1N_Lh!xEGN8Qwgf9mWQ+g_I$_gH9LApyvjX29ab0a<|s_uTY1?3eb2{@l|=#r zs*j!L#pUM2ngcCu2Up`%()~gSN7>xfgm`RAo3ZSj=T-?H?VA!A0{YL2N$d|G0D1mR z;1fQ8zdh9FW1?zlC_?r$-Ajbvso4LrVo0R$VHe9h*pp;m_;p#T8r1xiwsl#hI}-MI zd3%*X0*-!L&`pEF#hO<{eubTc*sbQTYU}d|bIEDgBVQejNbt`fU_l*c(~FFr|XY0^32zYiX&eOQ-&m1-63wU;Y2D7+322EHHK}q#Q5{ zFhE6l6(>X;8Ds0ONt>iY89^kn;(w42(U};Oh@v4AO$Znt8Knae7iAV%S`u*zF;q$b zC=``AgxKFmJ)|-}xB^L4D@DPj01!Pi6BNtl0CquL-C_YRz_#n`d*kbC_viMk?<+;s z^L?x1Nnw5*PlTi`l_(6Vfrp3325<&(Iv|P^NdpT^+7QhVych{JkCSr^c+*7K&k8mU zTejm*qWmy25C)B!frCaH+FD;j1}YPfIdV`xFA{K^kQrg( zJ&smkkT)R|sK}5vQM_P~JHs3_sNewuFo_J22T?GpJ`Jiz(}UP*3#dekJU{ryG=Q2P zL_#cyFnC`m7-s@U#X9^#-4{n4MrP+^kg)w|5R%}J2(Lit7t^X}P`?vVnk-o&HBSD?FXsXM z#w7fHzBd*$XqgKS&=BKae^TqJG8b+n5nzKL#BpHB8ej@!WR(g{5Q~6tP%x^H%uZF9 zbl^CWQ>(V#oc>|(SFK%ULr}1YPs~`cEnA}xrUV5aSGXXPlitVr6k_DD{FhK z>Ms&dwXbQG4IXeV%LKu;um2F{TrOR$Q;co&JtesSqa7P#GtJoJD*kD-gK(2wg*_{7 z#Dj9E=L%dzB}cSCQ`${r51>N1=MX$tvCW%RuCuAr+Kq-^$>UTi))!&-K$AVDvSvFT z{Mvgb)#GwCmB0dd!})_ECz0cO_LXlk6L1mcZ4-Ct@b|j8=<-UmPQqj5Eo9+xuW*#> zPyM1Vf3A1SS1`U3Tc-`|;@M)u-$efzf>7CT=4_gR;UNJte5*_6Wq@=|x@Jl*>nT6+ zVaL~<0xIhz2%qjsxkY!?P*{yS`yV;^4(YBhizkDG6cFgw~*>cse58LRz|+Rs!W!?fSNRy zkU$0wI&#GIk`HH=6aRubJ56)+SdB!l4+Nc=NcjRLh1_m67676etuH>ivp5k78Q~!8 zvpHR)!U&>C^Ok)!kTqLe-=C?}DA+H&|Gu)h4Rfbo!4?1_Oag3&4vy>s@=z;WBkuNm zt(X7GDry{AyiZSofQk%67{BbgVyPs_@r6@FQKxf@NT;~QkX6e+BrtoMo}})~f?Bsx z6~8~s@B&hP_+OwK+S_UB19S~Ea?a0dr7JNj6+R=nx9X}Lju8~unb=iLl9Cb!t z;anZo^~tI3k{cmgWXt}%=&h%Y{M#7P$py~Tq$!PJXat?*2PmL*kL% zewhn28{#B(_+h(wFxl&HYSk6hO*U-?GCK;=)(3d1Ve~e%-S^Q;F>GKs@h)5uJbsQF zO$=j{miGs);&cBolq%XyEp=<;!bYGe9P#Q`-fYqD(&EeMowhN1{K#E@`iO{rsg7VP zL7$K~n-Ub(AAqEEQoXn#u2D#CWiBE?`X92+DLBw4ded<-v2EM7ZBA_4&KF~1n-kl1 zGD#-3?M!SZ``h|&)mH7^be)U7>6<>M-+s<}@?UR4C8o9-Iu|pVn?{ULS`!a2hsyEX znfrL_0bpw7^4ta~wTgi5HX`vP#Q6(r8`4R-A-_~z<)TBo0)-E~%5YQJ{qkfkMZ8=8 zdtqSQxeJ5P_ki(J`txb$inlOTj(&MO*TGifGvb3wX!9H4iwfRL6lS=%9A=o*xeqj> zzk2!qPms*q#LUG1rOI@A4Nw~>G3B2s%IfJk|2J-f*94^l1?5O5=>w%rH_-yc25`-2 z;Y}v_Gg$5?*)0xNja}2+P=|Evv11p=!+!o+R~{ZG;Z#W+K2Fi+xti_j+iLrK>CNBX z@f9+>I{)swI`7Rp2k`7XD6^5z@C}`Wp!c(l60pJQoo5!jelN5L!npr9K| z??k`?2M(q{eL>-vIlyPR!IonJfj@)rf&Tao)bV>n{m`wKYq%%-Mbxev>+_>VXm+f|4T=9EupK>JQ9pOB3gk7y)Z72Wr~zxF~m)L4iLkpiz4c zTys&H^HIR&b8-B1Kz60fA%p1Lk&A#caon9>NGTH}ww`>yZchekA95<-BLVIdIIz>c zF*@vftTf4C(@+pXD{|b}|7gdOoqWDJrmMyvD|}w?J81caW02I*-{FI^sx)f!m@uOt z@R5k&AV!gk%&S#R?v_z17AEwaiSF6_jtSvtT@T^Ctd$b=^nI zMle{uMwOk9$lBVOhPoMZwXdi^q;rDlq!jqHsuSY+&tDBS{!C-ctdPqy-Z6Ev;)xa>X9E%v4;y)>pZ_}B%yLX#TD$zu&p0&Pr2-xl z{vKxJYNwn(OAK51AZ?Shsy#rSDIbEH3NWbMlS{B*?O5)L^r^d4eYjr=jyAdc_MV|G zG|$ayQ)^l-p;#6pfN;c%vDBKe*qLI}gtGy<%r(|&&pk>KbJqSQsz*=-8S;3eDeQS@ z$kq&Z&}g%H*JLd4)eptKqt;kBR<3iBS22}C@-h+9GmYeRb&g#YeCqQiI2@t`xVw#z8U)w?tK=B2QJyG1(5dxjj~ zdi0MhRD0kk!MjyU^C`;x^V+6|p0vyT#x4cwts=Pe&tRsu>1nBb(^jBUjNlS3V z(BiI4;WgX-iSjXkLtGIyEog?=F~J9n$@3lSS&ZCBYTr1X;~t}G(rr2caX$H>kvl5x z6mUFMY7N%?iBy`|HaC5ZQwGCw0c@Pgnj&$>@x8FK*edov(jc^Kb=@cg^aw2T)|RL3 zY)$h1pjes=k#gR3k5c|ZHXHJt{Eh~#ZwmshTKwe_`av;DLhn&>X9ca;bD!PkS7 z1Sl*bj%}Kydq7j-Z6DWW8t&A zz9rXLRn&M2IlES#jKfJ(ih)kO_rK*-h@%v-R?ckq8Z>##4sdapFw2zS>rcR|*^S(m zH)RPA&i^>VVjV*BUn+Ta{5b+-wn+H{bLxKftVYZuSF<7Pby;2;EG|!86SuAqF6Xoo z3^>iFQzKY6Hwzs~w`r0gFu|)!9N|s3w2QAk1Lu~78k-$n^FH<=COjgkaTyhaGDvQv zGK0MpQKicWCpa3D$91f8sg4T01jYwR`kZ@pnd@?`A5Nt6QW(x6wnM;+xB=PSkG7Qd zRu3>a+rR3PQth{Cjx49| z67dx^DVCMUOARfRz7}a&@vywU%rWFXzUqHlD!W3hS3@%G-m`x!KH-CCc3fY+uBHQf zknRPu%6y08uBim5Scj+P1e+xq#RD8n10C=h=jALvQuYmE+q{9y*3sy+`RD4^Nge_1 zl0U~dDCm25Jk&D2I%;trN`g|VhGtrCc6b^AYz^SFbUBQweI$%Q))eE<*h`$050yQ< zfhD%X^xeGSO=&zoors;1me0qjtn(7=vzs1B=X! ztP6dg&(>cAtj@t?ehl^Hz^|{=cP_avlTC-&8<2wB(2USfaz>QruVy5nK;l9t zh%4T)anRgZD=K=PD}!BWOl7mj`&lFUF>8el3_f4yV{WQFIC=yfle`M?2{t%7tDMP&w527O1sz%km!$E=&Q<#U6l$;jdo z?})PiU477$kI)26SNOgl;!de`Wj_CE;vX);Z+7J*8@1U-yEYXeRwVJg7Q^0k;r zwf2gLjdC-TeJ6=i7sG;iLwSRSF|w$nqVwvaMtugVGwXNI`S5+Q#pl~z$3tT3448Hc z!N?QH(E6NYhJGRtZed$1C&=@zBw>hO?8w)Sfjx;SdqHtRM)$9QY&kX^%@#i$4IZI7 zE-i*lbSEg+Z#dmZRXf$v#RJ|xbjkqD!gsR)VBP|Yyvsyv=t5MfclOUpA|)5q%+s8s z=%93+{Ix2qgq5B)y0!VCBaQEqNg*fvzNjx2C4OjTk~RbMaHmu>?SK{A+oiYRt0|Hl zfiE~He;`j+9pL$V!MaIIvX~Pu@tSF0w8C^`mPGL;qT;MZO<#HaVJn#SGFBG-TC$AZ zL+c5a{tL6T;JRwC);2+Jm7JA`REF(~NgU3%2QoY?7WY=L`pk_WMyxmFAvDTsn>?97 zk87nbt-LU9fsCe_Rg%*EHi0u(|4+h63?9Wg-rvpiQKTC$ooR2$ zHM*SGfG2$4$SN>Vc-<5E>0>dE24_*Ap*d53)SQFxZ2=`zL6WNQShWkJSjClO~2rjkEI_!Lu`_-;qb ziIr}9ttT3@bo#8WFAJ(0|BNfY24H7KbK)6*uLKz9Y(Hi}<{blcau+%S_l-%L`FFB# zo6AkvIAG@`#Lzuik)PWT&>UNgdwk403!6kmj}NsO!nKy?OLTt967r&y{lK-Hb1$nKr3#c*{= zS2pG}2@)H?r+I#En%a@bvTtk#qO@ZLK{_3vxbcz*rf0|8=HC_SP^^DAFa-aG&$J4i z6LHiU@M32{z^rseBv}V}|Ql$r%HG(oK-;xmxGB z!zu)*utZ>AC_WirY)P!SMhqYiK4Xb?(0z{gC&(WcyQ&&bG6W^;CWIFE-j{(IKncv2W?fYTB`8oQk0Y~m{i3!a`b?LkICMVr!@&m z_kA?=XWuLf?@_j4N)Rx-yW;N4o5$%5au|QMjCwbgq3uw}qLqbYr}hJ6D1CsAK`$lB zt;%-jp(CY5H@cx(=~^=OS3LDNCD1V5yCGsqhqiJXo{!MolC!tIlu*m{^H+v!Po`g+ zOH$-d1)M4{Bn&FHTnFY;$el{)FR$m?2bv3?#k+xD-o74Mx1s=h1Zep;qJB0uEQXBn zAgX(LobvX#2phw>HpOAbAICEqw*X{o{WPoCRG!zxzHF)%bb%R3hdIID9W0AJg#Gp7 zDR{TJwuj+B@DVjn7d7M=YJZ@tR*2{<+Yv23Au{WgyAFS-D0$Bnicr(dJRm9YcTv5^ zQ>T}HZggXN)&`Ke!+x~1U((wRq>K%O^p}ZCXoyjeqHSaS?9>VFj+wzdwW_@kueG!> z77v2JSFt11id(5%e{_)1Kc-H?Je!?<_7)+gM}4@N$p7 z!m8D9QLcTsJ|0@Av%knyH%5F2c=Cd*u3Z>e(jd$%#2K@?vYf{Mvb)Tb<=w%KBr1sO zNty+mlK^HOc$uniU&3*iznF5wd~lL*UEkG{&lp^_zAbsP8LYhiu~tu>(XG$g5;bC@ z`_H@*Bu3X-xV_wuauh~Hkze#i$-8R& zgG)o3!ihN&PK!Y^s56oC=VyJ!>a{G(;e5bk{%g3n>usC4)eS`M%Y4gd;4u+O;L4_{K_`-X`7sK~{MQ3piw`uy%Y>*#_y@0zi!_sS0imd`WJA5SGFB8%ipMgdAtQGwtZ#?(*anI z=eziZXNw!d#2bJV&iJE|qc&Nz4v;qa_$SS66}#wGSVV6b%DSQ5B>T~m)M;6w4Dz{j z{)5w+C5C2oRXj*H=D~;pqYdM;Ym}JJnSjF}t#Vb094Rql^=nn28%f7T*_MKQY9+$q zqM}*1^zJegs2WAZ48mSff;~!J8V5cg1v<-liKV;w8>YVURt4Tqk1G70GxjXEwag&6 zrpOt^?t&+Dryb>*qDmS!!5#T}UT`Lb#65F%2;4ox>(L2hc=n|!#76Q~Bl=zI;td6r z<%!gq5b}Fkj=qNtp3UN=`hRX23&xAGUJ~QGvFHWcJ;&hcUAgCeqPW~0`T+ek6cpc# zZT|V-nVPopobD~R%Q1(7*O+N@Klk2{kq(qrNN2=?`fd+)m4uWu)-){7NDAd_mf9|G z@G##zoxbf-{LArBYZ^(pxI7L|(Rjq%1b3>~{OvL?qo@yYyQD+zu*tBea_1;pn%oIe|myhuG*K(fI~oH=B+-`C^ZL}1=y)}YzYrj-@c=d|D+1D zp?H#&f~K}+12z)p4z^OCHd96XXu%=AT}6sJwanS^l2g|hwM1vR(i-IsKkIjR#D3#D zT;lSA?IRvOJOkryL`WSXm#^{x+LOEGN;;mcotHjG*zH9qG%yh4&Ts5%$DX}JXz)&h zf_WBoU^8k&Kr$OLaKKxFmD>h$MP-!`{({WvDp>E(stvD+Q>IipM?%RUL@9x=xP~=L zopsAk@Jm0yq^gV(HmN-LRH)K-5VogfT_2W_X_3Z^=Xz`J^bn!=@__u_yy)G5|MPQ? zHQs0=O4N~e3P_?nw_mu6Y-_V6)D`dHH~lCGQsQ$Fz+&oOhvTbrz7Q1k#PYNaVCr#1 zJ7!-v9?LB<=;gylp6k6{zM*|SiMcrs;s2f&@#B{T<{9%nE6w46W@b%2l`zang@`We z1^Ot}A`KWaYm50_&x&7Ho%zr-TciRLx%gR3)n_*;z-|I@rXxEK{s^jGIR#Z@aCT-m zEaH8XL3%g+k?D2HSbSX6Jwx6A8(MmGQAblyIqpjiw6oWk1P8Ap;U${ji{Bl}`A0N3 zo_CaLOlxs8O8httPmncN8+XZDLrFS#EKcH5h4%20gRKd5d*ifaw2$lYKM~E-A}{jD z4)|b`q*cn5N+Y>#ex7B#B;#nLY1H6L?aXSO4^A-qQU=#7q*2^`LG)o~kv zPQFZx?BenaON>%V3h2%g{52ZFL9Z6atDVdz;%yPidv=@-U*hUQl&yCe$f zwnhid?r7D>qm8S(K{N|FA(FH44`Lq6!{X)uRl^$LiJWWl(R%$sbgpUTZwwRQTm^UN zE$fPzF=gkJZ5zuGNr|2Cp`knU1Ix3b-+IF)-~eX*?g#Kz=zkHi`JD&g@cc& z4+XQmWF|Efm5+bjpK4k|L#P#SaOIL|VI@8s3!TfqSo)88QbJn`DVD88wB7r>3VC*X zt4EpAwgVV>)3fls6rtFv;2EGzYRew3lBK=tFCLYUM``LPSsqTHq+B;0S%hLc#miry z*3c)>YkFgS2BeA9HAT$(E|XQTH?n7B@yY*vIOE_c{-Y0OWDzBSkU(C!Pu5|$35u0 zjEQ)slTkdQ^9&9_j+=4yc}av=czNP;N@sC8>PNWVG=6KOBf>(`K^KM?5{dT)O#BU_^ z@R6;W)uI>ds%Qn65_8&`*5Zbiovz4C!A=9NdgGSecg!75fst9Wsg|cD|2wOA&Ou?) z3?(%qW_K`%_)+>Q+GD5=zaK=gk=CeLIaBJ^OqJ?hIqxpJ z(N`n{xHP#u;)Ue5oSHibAZ0sG;(1lPx$#zdNc5!PS{zv*UA0vrIbplhX8z5}C~STk zW*Cz@Kd=-7VIYWgUc89a_cC&V*(==D+l29>vQ_PVOae$o`C~nPgHA6`@HyC>SYP+0 z(mY4`1pV_7d~CH#dk(5CUDhD=oL8&S8mcBOlNW7~4OPc^ZPT>7ZjI0IUfng7(!ssJ zNCBA|53#01URY-3eD;2Tv$1CiLD^C)=1n=;G&!Pc3bb@AwTf9ulV6>idTggcd@W|B zwEkF4F9m*#LLUwiR_NRz4IPC{jr!Lcj5(!h;7N;DyehXKv=Z?sS4#+XI?2XIB|y=2h!ZUzS(E(PThCW#_g4N<|a^8|T{jyWb` zU6u0;WzaU$*QEa}nvgW_yJ^6w^y_(H_x5OiUM-8vaIy0`khAq(@kmh2%>HHj z<5a;^B@fDJ$qnVw@T^YVgRbo9Ki|ZqLycMSJNqw~rHr5<75J^iN4qvO32%x|uXFF4 zaAP3e%i3oaZ_*dX`pE{fHBDegI3~Yu=hT`Q;Z+Te8==J@&;hmJ3dEd{Ck1DK5g$MvtJIW#9)&05FmqCQ=JtyDB>+C8y*-BW+zm8O zv5`-Yma^C~TyGRj4eaGy+u+{z!+sR+Qp$S-_|4d`v9GrESL*fba~i{2!l_|~I*}AJ zJ;t0sX+N_PJ zm~w%&8GL81W?in95Rp#bB&Iih2hKBc{zVb+?&~pXa-F-?DQBxyG5)Qw*rdii1>344 z+d(k$7S4`&!$!d;qYeAdkZqC+S1sk05(aG-p z{j1D^JNUNr12;n#z?*cw+l94Y5f{}LTX{a=)Cf87G0*0!*l*Bzkp@^hZ|7%2hIu>h{}C2-!teQIdI2d6v)(ZDFW$T&#$BABp8{AZSKgr zMZ0ZFwl4vSBnGbAi(~@+4d(H*1?pZfLcTvPpWnBl;&h=2s=y4uk170ctAs^g^csy# zol4|TUy~dV&(csh&R=AeEM8{6GSydI{9?s?($nZN1n@rDr>Nz;z+xI@y@>je4}>J> z=ogBcMV3zV`{)Ml+;$E6qT#>)A; zdL|?fqeKvjgl`ekFQyM_DOF7Mkxmd7{;3AmVA}^FeTMfh69?zlC(D$fg2D&Ql&ZL#PZuBME*$(=soZ;=iG=09>Zj`+W8RwWTMaCA+3zzgyv;Q*`ujI(k^G)Z z?eVoE6e~OQR8JhN=*uQ?BhD6F8cyskeQ~3FTnEFkoh}8(tK0^xcb3T!f4g^&o{jLq z^b{)5ksP%Xzv!T<{dhk4;6K3pybH)R!_(fIXYkmC{yqQmRfJ>{$dz$i;ueOAMVk_( zZl+qIu9-t`B_*7D+hne{R(Xhww^Dw)UW!)}y2XTudr;rH@9doS>OfpvVweI7>Z~wo zOJ3wuwY-S-f>len(-gh^F;P}QW=bOX-dUZNBj41IyFb!yft%Ku*R4Q0{!d1|_!6}K z&Q&#DqVpUS!29A~O5quKyl35J(8x=Q&?t+LWwz}t_+9u_?9JD{2Q7Y1(kfm20IDJNe(@ zVv2iYhMH+kmK@nLW*_PJF)O?oAvP=lb2Wb2k?aCK&)*T+`+oSw=-rN#W|&?|&w8E$ zuU&BHS1(l6kgR~pHcGuo(3>t(s*#@p^Y<{Vee|h9NJZB4*=CQqXOf8NH2m}ph9VL~ ziut$N9f+s7;6^Kf*eWyI$s_*`k-E}SF}hH1SpGV9t#WeB^S8s=S@+4p&8c$Op2{v6 zmazGpcN_1s1gb`7BJ>%E3uv*=E<{#l!H*L2A@0xn{|tBf?aKhu2>VddbJj&!QzfVa10rXoN_kwJ50wx?1^ zh}Cc6#SJLkQ5M+voOslX@jGdj&$XXW?Inr%M6Av&ISN*@sbGL~pWr*u*Jw6)JWBR) zxb^Y98L2VDc}gtw+E#RShPJLAoi}}lJG0RKts^PwYlN~QSF9w1m_}{bpk<)*7Rlgh zy693P*cc#7jB^$c#nFn2)s_uXXZ}Mh^%s(_j{@MqxmQ0E?NP)gfZX9XA+TOL(n!YY z9M!J-H*1UUmVbOfRLrmnl}8BTO}yJ%zT?}(`8C2J>-*yGLdVaU4VB2jMcsE)d~)w9 zUSr*mCcif(9jXI#{nnJ#F8H_?Xe|S9wdS*`Fu6#KbSKsQW#9aAE1#Eo;U0*QEdP8CH6w5CbNLz5en)lZ|Huent4R z>=SusJO5c6ht>ov4VUyiMWqIiEww)#OrS|5dTAuM#eYup?zVGSee=pb{%B&R`=#iq z+8fUydz#1UNE8A82El9XS|%~8TTP;D`+b2Zs%i2Cn>JZf|D93wff!4J7P9cX>@Nj36+U?QVLg^PT%#mN0;fAq=Oi!X4sm)kU1 z*@oriSg=+!T7&ai3;K7C{V$%Oz0CLzmj{Xa{ihB}HXep_>IyIU~57!@*?ql6X7=9xmYOzB;% zGNYwbKeJ@d=Q1$da^E4>BX8?@#1x%fGDd9!=N;sz9X|yer($P5^VBG22J69|;x)}B zT=b_y#uZxfyx<`GJO8uV7q}Sfd&&WZ89avJ`n>E*UTp*NKl8JVoogHd{?XjnExjUg z66%vIQ1FO7wQ9u~mLC|Vx;VyJsyxd{wuh%Yja4(>%?wA3R~!lsdszw@kyphnmKIjJ zepM&Pa)fnLfo^X1=HS~qlJ5E3nJrO}l%7MSu67?1*!h895PzrcmEnY`r}F}h#BY;D zPtk}Gcru42E}|twxnc7CHIU9@1xnhq*-*=EojD9^=1k|FL9Yhmq<=r#B-lDR-XyRP zbApS=0O~DuH42Q>^2=;_$-iNnt?DPg1;A3{!s7Y3`IRLPOb*EK)i#40$kG3vA%jP2 zr#d)9AKJ>qli;3Za_wx77l{LTwnWi?Wzpo)le0`!0*l95ewZz^Gaj>(@mgZ)xzt&$ zIUVCMBELZ~Xjtb}2|-3gsplXtCE>JLDEQQ}eH1*o+hF$z{&`IMowOEWbYD<6o#$Pz zv(W~Zgq31-^zSXYxYa>7HMh|)c0)waN=HAto$`~h)WHIo30D+oUNR)gJyM- zyty@xcxT=1^;UpM>Y9&!;1Mh66)o9+sV^r?^QP$#{=6g=E`0?(r4+GJV-`nGxOI<0 z`xb%NH?-j=ZS(Ghi!(0FY6I=Kgg^d!NsfM$Q_Z+l!NH(9D@ zH{E#i!Ty*+nK$H@PP~9eZA-yQo=TP{?in(5&5Gb zp(yb&d;wE}G(BJz*^&9aW3d3A0gu(5j*tEN)A3nz117*VeMo35Da}~gPhrWPRY>oJ z_M^Ou|MGxaL!%H7k#uiFAWp{c=eh~}ewPz^>Q1g<^p;U=%sH8McQCN%2q`FEbMzEN zuko<{CxxXb>0_OkHT3U}75}74wi+?{;;jFSRB_@G|2ZpUWR6CJCE}m;{R1t^(7x4|oQKir zJNe@E{NEHDa%$yXac|F<5#KKTc|FqT#hDoGSt@r;411MLx|L}gX_Ra&mjpj7Tk}#& z&E|6)DF5bd&6z#>_enh@DVBR~MQ%5*difewe%7$xDP>R>f5-iH^Oq^MhW`c?34PXQ z*1tmh#m!9wYM2F-oKW}$_AvE zKv!i2DAbLhudyNa#*>I(aW_F*yVR0+7xo7B!Dgj#aNj|=EAsCHoTXJ**9$Kb zSovZ=TN{jkvy2rt_ObxUZ(|}-5u=2sZTGw3{Mb1)<>Fj2aag1Jt2a_+q+mc1(;-aY zBVnL~udN`qcEj%OY*qs!pk&^X^yz7RQ=2zypv(2wpB%gd1d;eUtH;RtlRr>CJxIKy zWjbu3VLI=IFdRpmTZOz{-^cnB8--v^3HQ`MGAc)9zZ2YNZ|q8z0Tm(@ju0j;^;8V_ zFiPQIu6dY9ITPQMb#X-UX(Ck?a+q@=q);CK{l+d&Pa#n1{d@~!Vxk(qK|(!>Q+6%@ z+M&xk+`;4A$7by3BwU~0Tu+ovk*~|YTe`|B?w&(WXzw-Rt>vG|?1CNMD;TWTD^NNpUPdab?qumR? zRXAKH{a!q71-q^y%-<>hn*TOPJ?X3lz>-ZS_Log+IvVPJ#=&Vg)gXxzwGIA9?gnS$ zt+to)UAq`q`<2{Y%Ds(~Ms_c5arO_;cxA}^>sk>)KH7n&(SMaEAYfO&qtI&o*ehW= zVz$8&U=di}RdzWF-M`15SYg!EfrXk0q{w4UeaCEOY=sr_5fOW4vCiU}?04G%u*7*B z@AvR%&wU2o{>`?GmS*FcmpP6LlWT9mJ8mP1mf-hF=;>lRS=b=;JSy`hYF9hGk)(h* zp4R%8jB)4){bYd!GXLHBJizp{E0B$b5qgw1c_vbxD~hF8O!fpWxv{x0OOor4_~pL` zYHRtmIVctK=9xdG#4CtO=5Im)-h;(zR1X6Z4*JmFmRu}4a*yRPAmM2s7T9vhNV#}I zXg2KijvbFWZ)xGfZGj5}b6pj>&AiR3mckae_wN#lMDnnwX-*5S5St_MZx^;T8*+2L z_J3oh*At8`xzdg~N}acioH6nj*@o7OBF>v|iHHTb>Iml~DUfpNuK__ouJO=Ga^>-G zE#xvDbzr2s>RA#-I|SJ^PlApxl2MK9-bh-Ze3p&1`R2~{(tuwZu0^8Zj}}+2-uesH zd+(u?;dH2P8G2YPi_+i!X5eU(H_&Y#cM+GDsW;@m{~dPQ zbJzyo@u^ihbZwQgtG#Rk$W(oj!U<8=kG;;!8Hak8W1IY#Hk&tbvUZ;^*6#{Z4V-6v ztsK*T=Yn4VwXrA!5Wm&`Y=KrG#<@ZNCJ|}F3M%80;>^O3n}MEPZ3+@P)QqToI(#lKPsr~wD{I=^2UnU%)?N`g-Ty&L z?u44LFjMJgNP}|>`0k}4J{8T{=-|f7{(AS4R<#2g3oF`Wr{F;QEZR48X-nbTvF7J1BT1>JGC-tYj21%Sp>VVvD0IH?YF1F zc-?8v#W8)15v3RA?2wJ*G0q=eS?1}fSOi6Moho8^845T8VwP82D8g@3d{7%VmzQn$ z@GioCX@0%|IR9yoK;SnTXn}M)8DhK$&;F+MH(b6vt3vuxCTK8}tfGvXl481k7O2(# ziQ6W!K(ir$yfR5xn{i%zVC&eBkpLO}*kSkJPHA4q^xLG@FeVED>>mRA!O`*2kr-rA z@AvEDg<(mG5vLO~dbkcWi7_!u5XdWtvTqP6NdXZNGAy`QcM!5;iUFYm_9lTlL?o^Z z$Sh_Y$cJ}kaIi2TUV9VUsnY!pCJAwTPkgih#M1;o4u9w@qK}9FF+mP{cpFB%+XrtV zOvnv?hXi*E=Dpby@EZ1_Y!@H+fjNM5*bwGR9Dt*ox<#DVhauTAeE&@GX^QfxR)_YX z6~p{5Ws^xXH{n}?RG2UfkcOa;dBrLmulf=z0uv_u1Ylaq`1>eH!z-;nqm^UVKg9gH z%Zq{C9poj-L#~ge(H&%sKUZAh2s>X~;_hId2r8ubfLID_*$y(r&@0wmp;>=`SPJ}$ zV`S3a9bVBt(tshMlP|m?$?6E)bodN3L-NGm& z+kxMFv&c~HkAdYhMVz7OTH+ViHEp-T!~ik#bKjS#^30i#9h`)KAj~kH33x_+(1vs< zPw`40HG(=VKHZRsRC1fG^lar>j@=MkuAI0lEup%n`L~|EpGKa{hZUS{^z?c7I78=> zp{MvO^(qI6>6^pEf(_k5Th#aqyV`=~LfD?~DPe%z=i+NGa@N!EN#Q(ta?y6q0nppy zN1!PYVt+yL=Bsa!*P^d&JV-h+o~am)vbRJJ_TU47Q(KZ4j51*WK_inf@w+ex5rsPz zKbq=B6RD_5G^hKJ@BY3Ht{qD5_^u#tG_7sVx2&V!6A?~4^G1u=`{Kxy-~X5 zm&#``J|~YxXR3gxTr{hEAKPWRSsUG(;r{U&JyrW}x_0R10Av5foO?vUw<;gk$OVyg zZ}H=B^ou|mWSHM3Qi|b@$$Hws8{RknMMwNHwMF5{BfJw^7q-3_WxrH`5@1{VlfBr1 z*F;>#IyGFXu`n6czTw?V8w9}0fY6TlUHtyyB)<5|&|)x387!Ig&XiqXcy)uYz{*#G znC{PFlHy?PGW8BdGm9}lGlr6o#o<({(UcVKFRe)Nx-$U*eMz+huhZZQcq`o|qId5C zID3L*)fz$0+WNev=oXJFCV+o|Y)_oCOvX@0GJb(wQ{mq{_!wuWufmDT`4RHp8S{-6cN_j7JU*2Oy7(0G@?E0&+80eCJ-_VezURLEMc zta-W+LIBLYpu>tQ=ZNz;!@g68Z1JUIs7Y?*4$f6!mp|MOiYRFZe89rhucMP)w%FB{ z{Q+i(-$`WOU|wWgERjFN?8<;)v$Q_D=nmxSBVid0^A_w+W&iXRgpHkHwH9NY7sg;X zy_~vILo*$#KSrs?k^k7nVY2{<-*B8Jk@|=I>&CVC!np}e9`}uEy;~pOqZ7Kv@0)R9lF0gUh2dMeIZtCHK%}~9OFB? z;pQ?Cv`#_VN}v&Zas<%k@SszT=Zg0HlYL9Ee|cr;m0Ux`NKk4)^LGWL$-Xku&(rI> z0=6fS(lt!Z>_oz}+2dcEx<2QloTzjf5}Jq5Qqp;vL*Qg>+<+_JOjsBCFf?iSg!;4S z-&bO&9{+uWAPg4UTosE`hA#DjxrmaV&B5b%p{5TKG}y`;wc58sbI2+aT4=0-D}#~$ zs(s`Nlj=mH|8YyhaUkfwQits`XeMqtf1ra3UO|2*Qs#+P_R-~@ zEUyO#kJ}aKrvXcB#--~9w!hisT{aZ$7=A%vjY6Gu{e40xdZ>6mI#>ZCajcruxQi1i zV4}d-<)$muO@<@fzmn_Da;_a{=RJXgsd=XsXi;%Iyy_#BBb?YVdbr0iRtE@C(x0KV6?G^IyM(#4QlmWnC* z%q(x6svjcrKFm7C7!)n=d8?AA_vK*!Y9Q6kTecWmla4IKpZ)xXf8ef>%-gzW%jc-wqhhZWu}}^5#2ii`p3{$mjl2=|=EQX6q;1ZYY{;^< zx~`yT^TPOlF%~aZXB5ysiYcYMvQ2DQQFc=bt~0)Xbw`UEHoZefgpYiFPg_+D{noab zRyYcH;d!-j!?WGGKz9`AKkohLV+oI85&N1$okIelv+MA5g5gL{rRDlWx{>`0pp1BuR%Mp$-ZCGe?fXCg%3S=|C7#|Qdcg3!43%*>aOQA^5qZ3KdmqJwlhvY9~wnNB93l%wS4AW-D1T-Q+EujSS+05@rW0KE( zRW(O<8M$--OnhS{$CI$x{WBha8TzfOJ9ZI&QnLqU5pTs3&xvCEGfEe+L`F+u$SJa6 z5s4gV24Sru#zx%Tj*(&oSQG&hEThvwhyHRYaszS-)QYzPN%L+X$J6~Q>UyW$@Pn5v z=&6tMgRNz@d&eIzw&?_MVm{AU{Wh)%39DYm;mmrnz3l3^;c@Q>Z=Qjof=uebD%u5q zZ|nnTGaH_>%bNLqTpS$)+Cmy~yv(nhx2^p7*h( z0a5!^H+MC@e%=GiMiuH97L~1lwHm$3YDc6@R60Ht{U*%J$HR{g_nx=4dUO}==+MJ8 z@vV#!HplXSkEx^xg({NEW<{|8OLUNb-i;_B=s7*^C-kkDDyCwa%*T4P$3I$QCO3CB zMdQ`-FC3&2oqPR*2c(0asLtflEso7hQ(tAT*ZQ6Hw>tm)P!DZ>SbowfBAXVrQJ^X5 z*lPH(F_7I-$7JJ&3!Z^d_F8MI__sr;r{>Mp8u;-CBMHr0Po#eub7EN_TRnPzC5z+O zD;UJ*t3E$SJ&;uGy)YisGBXqz0D&FrEm}PGo0Rc&i+W*l2{sE^m~XN=#~Gmg7aK5e zh0kf#jy0|xaT@1EZI^0(3wL1Miv*<)HOQj7uc^T=l4mtdcZ32SdRBM*2z^-jP2Img zk$C>5uJu_xb|X%qr+kth73=kXjkP1QX4~o%0l?2t5ES9o-^cWz2J)=G$zzoEW%9u3 z6d4Vc!;7B|7f{LzFFi4Glij0o9?6Ys_DCGY9VJ7pDoR?7jn||av7IzDOttvodHL#% zsZv~~%-7kKklxC&cGccYEsg^b$qjM;WXD0Sa%tnfLF#*nP2jBO)A%ue6A?1!v0L~- zm0`r`RFo16ExLk|AB>9!p^u3lD0}NC4+Z3X7JprBSEsy;BqDy!i>zG?DcM|E73?k; z+l@DHICz>)FYc_#sBX!8Kwr<(+0gQchkLDcekhAMXl`Kcts{f8!t=`m!$^UipO(*u zxbhRRy4AdF6NxGPv+OBV`JShdK! zbnKlJFb{CWCHOlZX)2D1i+Rvv)2yAcJtDh5KsFqfdq%C8ACKnbxYylIEcB#I8Y4GO zCNyFOW3VNIDVLCAMgBHiPqn8QVsb7eR-gGy&p=cIm%g_=ac$Ns5~u5Ko(HZ)BEQeS zVc{Rl?EzI5rf3;|E99k2sjh>uB=TNTSv)ZI*~<#|`k*FTl%ew4bBA=n7iyhW;JR)v zZ*x6`vro!5-8|K19k%}@rknb$HX^?TDeF{%^AJ}`%Ra)4)5?Ls-c1bl2Aga=>g^Zk zBC|}`q|pA+8^5kkR5`^$pRCJ;*pwaWxXRZ z@k6gLko;_!OYoNR7#sU$X4=yhJT;Jr_egg9>9J)#v6;6$;b!ct-jJfc{z{YQwG3r| zfapLZj#Ax!*oVlnXwdwDPPdsnO7b~5{%g{W}hxRQ5mg_c0#(h+HsCQp%sr9w4=p!2FlW@oNIBcVoPuai{ zgAL*anbP3F9rlvU@zm&`lG}R=LE2Z6W#cB_`no88vqI04RdJNKx^mt<^BXzqGBFEO zySY7Dn7&%)H}{PCMySjXpRj7~`{2Bu^h|@<=xW+nbF=!xGY%`6RGz24iK-g{!hE|V zXTH|88Wc16NMht_)a(37+lQFt3@aYqAMZ20?|<~B45L-)1I^>UVxtO!w5nB+C6eXP1INxR;bOIf6gqdlMLzY(A|xQ~ z0HL8zD|oM*kjA^AOz+|Oxkue*3Rf~IzLJX(y$!KuMrVOP^A}HKJHz*vAX?L%d7u4m z&~nceqZ#*L2qHt zZB1xF{s{kl;62e8uE)Fedv_s)%(6TrG26L_c5^r5Mwm2>@6W!_x2%+TBS=TK@47J< zx7#df8j*;>Mm&MYq9!lZ*3MwAi1lrMLi#vnR~om@fu7!Yfl1@p&*0BV#1RPqp-e*V zoMTracqYwYf1f<(j)tPd0J5}*-cf~v^&>g@rtX{APj+GBdm8VFdnKl<64q}QbB4-0 z$|{nFx}0hF*)or7uk)t;2#~qt-+@Y|KZ?}ln#LZanBlFau{@W>zKm|ZbD_bX_cW>?gGg5i51^i+>fQ*8V57G`$4*qkZJI`9&QMK3yf9zxI*D3Ylc9Qa;twX8VK z_|`eoKS}N`ta~>0PS9nay7Pg^(mHeIkUCA1M$54IOYP3>j7aqEHn@ZK-Mat0ZAMD;tYeig(f%q64c+?zENv6iMI2|m14s^e$w)DS*J0C-1QDM{JYy5QXN43I&(Yk7b|J0JCy(d4y(z?eWXb zRx|iSPqIm?dG~F9rB^;hu&Ly!M1t{4p25egRy>c)#c`5FieCHYy(5rdbUmVPD@gMP;6OBC{&$7Ru+Iy{vlI#$#<*cm;q;7wolV3 zHlMwDA#|FOQv2D~qEHpoLbGg7wb2&mT#k>&bNSL;?(=YevRnC%sMQ|?cthlw#ToIM z{A}<24*_53w8AV1U)P{v$cJ@|ak#LNH5Hy`>2WA_zGNI(GQydYJI(q*sQ4o8Q55IE z1Y0uQjDlK6Ih*nqHd$=O*0F;NG%TrvOw$SG0*2G%!+VZ~b;a7TMPxb{bZz3Jz^(f0)S zD%w1gLA>uzE4y8!PaTCnU*br2k=XWqwVH!);lIH4j|f|g|GqfaFPoRaPZu7kUKi-d z3OM-bZSGX%SjT>Xj9TVSZdcYop3C}oND%i}khR^yOFQg6h1jUK$v7qzD2`i+R=Sdh zE7Zn+B&Ot?(W!14%i36oy0@OFpS{R#{ZzVtvWlKJt4#kYr&!gvWu@T{+u+DDOiwJ{ zI`$9c*CdGW&#_#OZ@!9%2z6=EX|A~Dv1JF_y|!r|y0fSQ?6|Xun(s!+X~4G6KZa*@ zpLdyVib=e;xO*qc#F&0tsUJtUoXWV`0$?Z6hl zCE`vSx}Q(dkQGwzC*gj5GoZt9m_3z$HwDnvle)kAqo%aC#GTuzaP$DHzfWZ_8IMh; zq`waxTS*#UEMN9axE9|a`>UA)6-%Hf2K26{=F)^2jUAQ`HY6fCtFSg>@K;GkDA?%i zDJSqMiZ#cBlkwfDRZsBr@6!qH&iF})+ol&Yi023`*=BhpiqbPuYxGICD%kaZW1ZZT znPy@@j)#u2V?FL;l=@3gR^mI)tRAS4bK^Z!?zLrMhHZQXxzl+M6GSCi6;^4RL3J~Q zWM2-<#(n2F-|y$$HswpS$RV(G)z>3D7!xTGS!bm4vt@hCOvgrC>E(*8?R|8--K+J1 zQ?sJcO!~OLM17;@^+&Q>rz@a;^da}A7V0rHPIkI`T${BY9r;zR)VJWJg~`!0y#Bex zw4@_Am{{He2@~^)KL4@8Og|-cPyHYl_>$m2b(E|DC-@=qWAy`$nzt{YkO(=x}-&n$v1TP?J0`>8I_Zc|FqUB#K2n&37+^(T(+P7_Jn$=#1lzq}BC+@0{q zfZqliUni^0ceAEW1uOB*`4bnHA#kC}C~iZ?9~R4=VU5$R2jQFeG&{X3x{xGQM%GWd z@+pBCBlB|lKaYXbYecDkr;c`s;`5A6O%Tus*?p^u@OcjToQSZ(%dvPV;+E4%*y&op zVkZ8syM(~;HX;8DGl8}nb@Y~cYd0&hHx<{_ovq``MWJ|JI*~*NF9!Hl9CWO*7iCn9 z^xUpv9LPJdOLdqCTi@vpvlmOjRXd_X0`4ywKIIyXKWQFu%`?P*aMB(I^o$ZvBS5W`_e#mQ zB|~novWxCnb;Nyz#3_FBd5|2i{->eSBb7~0C4a)(USdfnB6YVc_r@%yYYYD4=*{$Wp;*t|Y=DvHZv{RbQ zn){NTwYm}KtlrtWOXFPx%Bc=Hj~u=( z18o#r8w?D8h4khX*ftJ}RZ#UjRNX8vV7nz0lp^%645x^o-q51x*HTGjON{xnb&AU$ zdX|KgfAbv;9{H-1cgL?>i4OQ#tl0{?K&S~Rj`XPCJF5=wvdd$~#*6ge{eS!b{x`w@ zhy*rH5D>y0?hHaW0{#nj46^iPZe(+Ga%Ev{3T1AWuet$t21-{$Nk&kYE4u+_3rbf* zNk&jBLrqdRm(iL57q_�c!&SI5?LfzX33R6ytQnu8*{haon=lpe^ zv(`WB{l52mfA4yKpP@e8-_((X?uT4a1TzImpe;c2@}mMEi9#?mr12mI2BU~G1A}aT z0no+<1RMpSfEfhvCi$nlHfCV!#U_TTJBLwn-A9o}K1+2c5S%QeK zttg1c$4vpoxJeTLx5z>fju2o$Aq292H;SJH;ZFV=roI(-6>vD-4DNzFp3$GW3@*$O z{ z!r<_s#X5wrzBPfzwrGLuyxlp-GmyA=n~N{tZf#5t4slp2O-$vTHy(P#UU`BHw48%Ov2y*%Ct)kD`-4Y zmEdw(T&=WO-YK*x+xz16-Zs@kk8|WXXF5D0H$SW2HG8&5>#w6qqk7SEy8N`(INvT; z>A}eC!v6WusC}bF2U>J@y({t(zKYl&J2b9#rLk}3t);wA&$G^|{GjrG_L9jv<7ISX z=YZGCp6bip*d5hyqd1vrwac}Lvm@njy^*=TpL$_rRjNhGP_%k}uHw*xLkVFi%FV=I zr_fe`=Im+Z(!BZLnKwP(?OrA7r|v4vk*mF~AouiyTd&^e(s^gPSrrQ%HFogos#Mq#jTOAuce;c zpC{ZV{r;CBtK3Pm7YC@G5jk!&SvBaaCEjq(%$l$2L`W$4%X{&Eh!1^*@29S}5`s+P zGZpNkIXzb%KiFk|U@T*$uYA0L)>@Sbbx$QAz;6k=eAb?6eVH@mx%I{6cVm_&$cx7V z?)#%9>pt&`nrGen+bzeFmDu*J%njRS9XrqM6KyRB&wJjmtmtW+_atB8leO|t)d$}X zy7y&2?NBOm?mVA=T&ck=RJNDyGFTo^>&C%up9-9duziq|v|3zIQ1KzLap_BGe(lF= zITb2liQGo-UqYx=hYET&V|k<|i!hPL-Z%c8_KDR@k2&M&ykij_Pcm*lwDi3{Pu!Gz zHT}KIlJTnZeZ@k9SkX>UiQYA1%XO)K))h6jmCo9l zoYvr{HnKwk%jn%K{onUEsrmePsqRVH<<$e$p@?WIsD^JS)ozh_D-)#x2?4w-zgBJb zL{mX`Kyk2(L56sCDEvf^c@1oAIyt!h)UV=W!^$>_X9n5*=j$yXrsFlt>!Ldp0@w7+hD7U4lxNq@8{@X-#^o z-O1-iOA@M8^WE(V&X2V#jPHF^d3N7=*HicBHg7@%OOBF_nqQ#FO~fm~XAh(oBvk6D zm``{aSg$SqUj4XAOejd(*iyb~tH&3ezr>y(TCOmlFw})#Qjee3KLM zb)50NNnCBO+?~`c`+;s<*_-TF^*z_gD^*W6TdqIuX)P%UnywYggJJ9J#o?*!$`fUm zww%nF36p5%?+SKEPtJ0j%+%ij_ba63c|{L;_Q4JtZ?VpcED)?P*>m+fovbA*GD{?R zZrnkCLkk+eRm)*(^aS?!i5fRPD>BmX_5~HuT&#>y8x73tAoYrHV zTN;m@xmff{ZAFR9`QrKapC&ZMlz@zVlcznNIiW|dwYO+84$|~Hbe5#C#fGb1QQX9T7#qfsSmVv~D+ zvztX}kK4oR)U?fx$>M}ZDn_s?Y3||bg@cNN=dSjE;etu~)IgGD>G%_idfzr#HW=Su zE7!oG5>3pW5iXe+t&*0sOq-CuTe(*}a;cdfq@_-}I#ytu@mrfggWLswi63iXmg^L0 zs;!Xn!=`)grr6ZSBpr=1m1MHaXWsKk$_bBEGcsx=Eio%PSnFbx!P7>Ew;Mdu^VEns zN8Vj~+B-M=)6KU0c?K~($OY}D{D%+W{{sIL0!$9X;9)42!3!t+15gwvt(OhQ0f7cY zM?_gnSC^E>0cQq8M?_gnSGNJk0Ym`-HJ2g30V-oyh4lg)5+6p|37FaqCzQjiZ2Pfr90)N+7u z0h`C?Abc)=hv5i>gi1qV@>mKu3te<19uO!YiAhl$_@h)TRMHw!Q~`nsDF!JG69^Ov z5TrYi0D@owBom>G$v_Yw!=x104&@lmVCf8r@fZT|reT>{HPcFjWCCppIMXIw0Buo5 z;0g_p!59WBfS~V!w3C0s)NFB)TA>I)l{$G{Nbj|OQ6;9({6!#?Dm4X3;7`aPiO;5n z!)b5+P==|Mv%6vnRbWy9E>}R{hPX4?tGUw+EJ1`NL74=jq_H3dRV2VE9OAOsR_OGm zjIab@K_S6H*XgNF^&}{UQz04^1nhU@sTz4#(;1Oi64=6Kve^htq`#Tnwpn-i;8H?{ z;c~!#;jRHFNunACo0j5mxgZ$<7%qcJ04C9fSxlUu=p%qmCI!S0Btth;Hee|+T%Djp zrvP^kz*3PIZGHwp5Ds9GsBCIrI`I9U_4X!`lHKTs>E_8r0K(yN0MCPy@^@k=j>W5? zcmv?F*=!GFIuEIuBq2^sJu*7TnK}le!-p_`2}&8=U4+ytV@J`qnWuL79Bn&2pSAFH z%h^ZW2A3o1c9meVlwhtl&`wTO3?1pOIoMi-U+tQq-PZ_`rXxONZb@3_C@L5{$>0Ia-ev>!>aCahtw7$t?XCt%}48B-tRJh zG+7yRXr;Y1uluAy?;LXrP46!qfnu8mcq;pFf7PuVa<5dos&10@d zC0)#N%g*Y6L6gSDCBjy(w~IzyEw^B9$xijnE{jL*y=E2kK9;Cr?;9HG2M!F^{VW_b zu4f32ylN@+x)R4-sz`AySyVLe9 z-_`1`)00RZGfk>m9*&*0-EhJx{Oqc0Yx9%eE_4W+^Fc)B(=}~Pz4*@Zk#*y_0bj$StaH-LtRcsqwIQaWTIKgxuT3B1#)mfpJ#~yvdOUV$YgoUPzmw2A6xo}|8;CAX~ z9KU|oL`wD*u*IQ;fDVC4lFn@7-&QA4 z& zL8NuaOkg0HK$u_x3RNf<1yl+(Vg)S)1VLOtrAm>TAW$ueC@uz}E`bUUa<*~g zXX($~U;FILpLx%FzVn_r?`KB#{nW+dy z@By(t!H_KCLn|7VM&YIa%DhVp0QU$

}+FU?IVOjw`{3!MK(GhO5QmY?(;J1;z97 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 VF~Z{&J-g$0k!knRIFmC_= diff --git a/bn.tex b/bn.tex index a69c13c..3c07991 100644 --- a/bn.tex +++ b/bn.tex @@ -1,7 +1,7 @@ \documentclass[]{article} \begin{document} -\title{LibTomMath v0.19 \\ A Free Multiple Precision Integer Library \\ http://math.libtomcrypt.org } +\title{LibTomMath v0.20 \\ A Free Multiple Precision Integer Library \\ http://math.libtomcrypt.org } \author{Tom St Denis \\ tomstdenis@iahu.ca} \maketitle \newpage diff --git a/bn_mp_exptmod_fast.c b/bn_mp_exptmod_fast.c index de42ff8..54de53d 100644 --- a/bn_mp_exptmod_fast.c +++ b/bn_mp_exptmod_fast.c @@ -80,7 +80,6 @@ mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) if (((P->used * 2 + 1) < MP_WARRAY) && P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { redux = fast_mp_montgomery_reduce; - } else { /* use slower baselien method */ redux = mp_montgomery_reduce; diff --git a/changes.txt b/changes.txt index f874a2b..5756d6a 100644 --- a/changes.txt +++ b/changes.txt @@ -1,3 +1,7 @@ +June 8th, 2003 +v0.20 -- Removed the book from the package. Added the TDCAL license document. + -- This release is officially pure-bred TDCAL again [last officially TDCAL based release was v0.16] + June 6th, 2003 v0.19 -- Fixed a bug in mp_montgomery_reduce() which was introduced when I tweaked mp_rshd() in the previous release. Essentially the digits were not trimmed before the compare which cause a subtraction to occur all the time. diff --git a/etc/2kprime.1 b/etc/2kprime.1 index eb12565..e1384db 100644 --- a/etc/2kprime.1 +++ b/etc/2kprime.1 @@ -1,2 +1 @@ -256-bits (k = 36113) = 115792089237316195423570985008687907853269984665640564039457584007913129603823 -512-bits (k = 38117) = 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006045979 +259-bits (k = 17745) = 926336713898529563388567880069503262826159877325124512315660672063305037101743 diff --git a/etc/2kprime.c b/etc/2kprime.c index 47b0e1d..4f1d4bb 100644 --- a/etc/2kprime.c +++ b/etc/2kprime.c @@ -7,7 +7,7 @@ int sizes[] = {256, 512, 768, 1024, 1536, 2048, 3072, 4096}; int main(void) { char buf[2000]; - int x, y, t; + int x, y; mp_int q, p; FILE *out; clock_t t1; diff --git a/makefile b/makefile index 15972af..a835a2e 100644 --- a/makefile +++ b/makefile @@ -1,6 +1,6 @@ CFLAGS += -I./ -Wall -W -Wshadow -O3 -fomit-frame-pointer -funroll-loops -VERSION=0.19 +VERSION=0.20 default: libtommath.a @@ -103,5 +103,6 @@ clean: zipup: clean manual poster perl gen.pl ; mv mpi.c pre_gen/ ; \ cd .. ; rm -rf ltm* libtommath-$(VERSION) ; mkdir libtommath-$(VERSION) ; \ - cp -R ./libtommath/* ./libtommath-$(VERSION)/ ; tar -c libtommath-$(VERSION)/* > ltm-$(VERSION).tar ; \ + cp -R ./libtommath/* ./libtommath-$(VERSION)/ ; cp tdcal.pdf ./libtommath-$(VERSION)/ ; cd ./libtommath-$(VERSION) ; rm -f tommath.src tommath.tex tommath.out ; cd pics ; rm -f * ; cd .. ; cd .. ; ls ; \ + tar -c libtommath-$(VERSION)/* > ltm-$(VERSION).tar ; \ bzip2 -9vv ltm-$(VERSION).tar ; zip -9 -r ltm-$(VERSION).zip libtommath-$(VERSION)/* diff --git a/pics/expt_state.sxd b/pics/expt_state.sxd deleted file mode 100644 index 6518404d5fa6eca01b4457a813f85cda074c0915..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6869 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 YjJ7)dxd~WU_~#EhHWpUWwTse!03-Pj!~g&Q diff --git a/pics/expt_state.tif b/pics/expt_state.tif deleted file mode 100644 index cb06e8edf17017dec815be222c845f1b0a938e07..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 87542 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≦RYV{r={iMn(Ta_rSwB@dOoKkT7uoB zm>DX9w4o@~>(T4B6{=OK>K|NB_%L#N5_JJ$;s!Q}qJxUPIv=G3bmrL^6**GGA-Da^ zCB;W@?#|o}7gXp1E%T~qJTaVw0a<51tcNsB*noTLp+>XomZ1Ci_CA7uD{ibGLLbrc zT5N_{Zw1xom9I4Oe+VzQ2k5ll zA-%4~x&F@$@1$Lx7H*QE4ps;-706f=e)ER!+<0`&_7;vu*;d5e1Hdmg$Ck3Xz9$sC zT>ES{8$3`HsFZJ6Uks3y*oEzf$AQ*8vU5r+r>OaZO5$V<)eAq!DSxli{Vj1eh?-@R zM7k^F;Y|5aSD@rah|h1E#LmpZ{%oA72Ak^saDSUZe9flmts$QgjZS-A>rwtj1TI?h zJ^0)V-fJB_dBC+fRKDKg8^@9qC

Gz?-?J@iV6)5~XACr^a8KN7>Cj@YUK!?WXXd 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 sliding_window.ps - -expt_state.ps: expt_state.tif - tiff2ps -c -e expt_state.tif > expt_state.ps - -sliding_window.pdf: sliding_window.ps - epstopdf sliding_window.ps - -expt_state.pdf: expt_state.ps - epstopdf expt_state.ps - -pses: sliding_window.ps expt_state.ps -pdfes: sliding_window.pdf expt_state.pdf - -clean: - rm -rf *.ps *.pdf .xvpics - \ No newline at end of file diff --git a/pics/sliding_window.TIF b/pics/sliding_window.TIF deleted file mode 100644 index bb4cb96ebff4e06478672dd3583bd26a51d85b5d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53880 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 DSo1$6 diff --git a/pics/sliding_window.sxd b/pics/sliding_window.sxd deleted file mode 100644 index 91e7c0d9f43b612ff0a59d86a71c8928fbd695f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6787 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 diff --git a/poster.pdf b/poster.pdf index a1ecd0669b2a48e1e6ce0339b209c7fd9284a6c8..629336c4d8c5db4aafb644071da172d6174b1ce5 100644 GIT binary patch delta 15897 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 * 2 + 1) < MP_WARRAY) && P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { redux = fast_mp_montgomery_reduce; - } else { /* use slower baselien method */ redux = mp_montgomery_reduce; diff --git a/tdcal.pdf b/tdcal.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1566a9ddc02773902d1db4ae33b33c97611efdec GIT binary patch literal 56671 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ΞNw%6&qBB6kWsO`LPyp`;LRw*-Sat(?ny)zpO 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 -\def\twiddle{\raisebox{0.3ex}{\mbox{\tiny $\sim$}}} -\def\gap{\vspace{0.5ex}} -\makeindex -\begin{document} -\frontmatter -\pagestyle{empty} -\title{Multiple-Precision Integer Arithmetic, \\ A Case Study Involving the LibTomMath Project \\ - DRAFT - } -\author{\mbox{ -%\begin{small} -\begin{tabular}{c} -Tom St Denis \\ -Algonquin College \\ -\\ -Mads Rasmussen \\ -Open Communications Security \\ -\\ -Greg Rose \\ -QUALCOMM Australia \\ -\end{tabular} -%\end{small} -} -} -\maketitle -This text in its entirety is copyright \copyright{}2003 by Tom St Denis. It may not be redistributed -electronically or otherwise without the sole permission of the author. The text is freely redistributable as long as -it is packaged along with the LibTomMath library in a non-commercial project. Contact the -author for other redistribution rights. - -This text corresponds to the v0.17 release of the LibTomMath project. - -\begin{alltt} -Tom St Denis -111 Banning Rd -Ottawa, Ontario -K2L 1C3 -Canada - -Phone: 1-613-836-3160 -Email: tomstdenis@iahu.ca -\end{alltt} - -This text is formatted to the international B5 paper size of 176mm wide by 250mm tall using the \LaTeX{} -{\em book} macro package and the Perl {\em booker} package. - -\tableofcontents -\listoffigures -\chapter*{Preface} -Blah. - -\mainmatter -\pagestyle{headings} -\chapter{Introduction} -\section{Multiple Precision Arithmetic} -\subsection{The Need for Multiple Precision Arithmetic} -The most prevalent use for multiple precision arithmetic (\textit{often referred to as bignum math}) is within public -key cryptography. Algorithms such as RSA, Diffie-Hellman and Elliptic Curve Cryptography require large integers in order to -resist known cryptanalytic attacks. Typical modern programming languages such as C and Java only provide small -single-precision data types which are incapable of precisely representing integers which are often hundreds of bits long. - -For example, consider multiplying $1,234,567$ by $9,876,543$ in C with an ``unsigned long'' data type. With an -x86 machine the result is $4,136,875,833$ while the true result is $12,193,254,061,881$. The original inputs -were approximately $21$ and $24$ bits respectively. If the C language cannot multiply two relatively small values -together precisely how does anyone expect it to multiply two values that are considerably larger? - -Most advancements in fast multiple precision arithmetic stem from the desire for faster cryptographic primitives. However, cryptography -is not the only field of study that can benefit from fast large integer routines. Another auxiliary use for multiple precision integers is -high precision floating point data types. The basic IEEE standard floating point type is made up of an integer mantissa $q$ and an exponent $e$. -Numbers are given in the form $n = q \cdot b^e$ where $b = 2$ is specified. Since IEEE is meant to be implemented in -hardware the precision of the mantissa is often fairly small (\textit{23, 48 and 64 bits}). Since the mantissa is merely an -integer a large multiple precision integer could be used. In effect very high precision floating point arithmetic -could be performed. This would be useful where scientific applications must minimize the total output error over long simulations. - -\subsection{Multiple Precision Arithmetic} -\index{multiple precision} -Multiple precision arithmetic attempts to the solve the shortcomings of single precision data types such as those from -the C and Java programming languages. In essence multiple precision arithmetic is a set of operations that can be -performed on members of an algebraic group whose precision is not fixed. The algorithms when implemented to be multiple -precision can allow a developer to work with any practical precision required. - -Typically the arithmetic over the ring of integers denoted by $\Z$ is performed by routines that are collectively and -casually referred to as ``bignum'' routines. However, it is possible to have rings of polynomials as well typically -denoted by $\Z/p\Z \left [ X \right ]$ which could have variable precision (\textit{or degree}). This text will -discuss implementation of the former, however implementing polynomial basis routines should be relatively easy after reading this text. - -\subsection{Benefits of Multiple Precision Arithmetic} -\index{precision} \index{accuracy} -Precision of the real value to a given precision is defined loosely as the proximity of the real value to a given representation. -Accuracy is defined as the reproducibility of the result. For example, the calculation $1/3 = 0.25$ is imprecise but can be accurate provided -it is reproducible. - -The benefit of multiple precision representations over single precision representations is that -often no precision is lost while representing the result of an operation which requires excess precision. For example, -the multiplication of two $n$-bit integers requires at least $2n$ bits to represent the result. A multiple precision -system would augment the precision of the destination to accomodate the result while a single precision system would -truncate excess bits to maintain a fixed level of precision. - -Multiple precision representations allow for the precision to be very high (\textit{if not exacting}) but at a cost of -modest computer resources. The only reasonable case where a multiple precision system will lose precision is when -emulating a floating point data type. However, with multiple precision integer arithmetic no precision is lost. - -\subsection{Basis of Operations} -At the heart of all multiple precision integer operations are the ``long-hand'' algorithms we all learned as children -in grade school. For example, to multiply $1,234$ by $981$ the student is not taught to memorize the times table for -$1,234$, instead they are taught how to long-multiply. That is to multiply each column using simple single digit -multiplications, line up the partial results, and add the resulting products by column. The representation that most -are familiar with is known as decimal or formally as radix-10. A radix-$n$ representation simply means there are -$n$ possible values per digit. For example, binary would be a radix-2 representation. - -In essence computer based multiple precision arithmetic is very much the same. The most notable difference is the usage -of a binary friendly radix. That is to use a radix of the form $2^k$ where $k$ is typically the size of a machine -register. Also occasionally more optimal algorithms are used to perform certain operations such as multiplication and -squaring instead of traditional long-hand algorithms. - -\section{Purpose of This Text} -The purpose of this text is to instruct the reader regarding how to implement multiple precision algorithms. That is -to not only explain the core theoretical algorithms but also the various ``house keeping'' tasks that are neglected by -authors of other texts on the subject. Texts such as \cite[HAC]{HAC} and \cite{TAOCPV2} give considerably detailed -explanations of the theoretical aspects of the algorithms and very little regarding the practical aspects. - -How an algorithm is explained and how it is actually implemented are two very different -realities. For example, algorithm 14.7 on page 594 of HAC lists a relatively simple algorithm for performing multiple -precision integer addition. However, what the description lacks is any discussion concerning the fact that the two -integer inputs may be of differing magnitudes. Similarly the division routine (\textit{Algorithm 14.20, pp. 598}) -does not discuss how to handle sign or handle the dividend's decreasing magnitude in the main loop (\textit{Step \#3}). - -As well as the numerous practical oversights both of the texts do not discuss several key optimal algorithms required -such as ``Comba'' and Karatsuba multipliers and fast modular inversion. These optimal algorithms are vital to achieve -any form of useful performance in non-trivial applications. - -To solve this problem the focus of this text is on the practical aspects of implementing the algorithms that -constitute a multiple precision integer package with light discussions on the theoretical aspects. As a case -study the ``LibTomMath''\footnote{Available freely at http://math.libtomcrypt.org} package is used to demonstrate -algorithms with implementations that have been field tested and work very well. - -\section{Discussion and Notation} -\subsection{Notation} -A multiple precision integer of $n$-digits shall be denoted as $x = (x_n ... x_1 x_0)_{ \beta }$ to be the -multiple precision notation for the integer $x \equiv \sum_{i=0}^{n} x_i\beta^i$. The elements of the array $x$ are -said to be the radix $\beta$ digits of the integer. For example, $x = (1,2,3)_{10}$ would represent the -integer $1\cdot 10^2 + 2\cdot10^1 + 3\cdot10^0 = 123$. - -A ``mp\_int'' shall refer to a composite structure which contains the digits of the integer as well as auxilary data -required to manipulate the data. These additional members are discussed in ~BASICOP~. For the purposes of this text -a ``multiple precision integer'' and a ``mp\_int'' are synonymous. - -\index{single-precision} \index{double-precision} \index{mp\_digit} \index{mp\_word} -For the purposes of this text a single-precision variable must be able to represent integers in the range $0 \le x < 2 \beta$ while -a double-precision variable must be able to represent integers in the range $0 \le x < 2 \beta^2$. Within the source code that will be -presented the data type \textbf{mp\_digit} will represent a single-precision type while \textbf{mp\_word} will represent a -double-precision type. In several algorithms (\textit{notably the Comba routines}) temporary results -will be stored in a double-precision arrays. For the purposes of this text $x_j$ will refer to the -$j$'th digit of a single-precision array and $\hat x_j$ will refer to the $j$'th digit of a double-precision -array. - -The $\lfloor \mbox{ } \rfloor$ brackets represent a value truncated and rounded down to the nearest integer. The $\lceil \mbox{ } \rceil$ brackets -represent a value truncated and rounded up to the nearest integer. Typically when the $/$ division symbol is used the intention is to perform an integer -division. For example, $5/2 = 2$ which will often be written as $\lfloor 5/2 \rfloor = 2$ for clarity. When a value is presented as a fraction -such as $5 \over 2$ a real value division is implied. - -\subsection{Work Effort} -\index{big-O} -To measure the efficiency of various algorithms a modified big-O notation is used. In this system all -single precision operations are considered to have the same cost\footnote{Except where explicitly noted.}. -That is a single precision addition, multiplication and division are assumed to take the same time to -complete. While this is generally not true in practice it will simplify the discussions considerably. - -Some algorithms have slight advantages over others which is why some constants will not be removed in -the notation. For example, a normal multiplication requires $O(n^2)$ work while a squaring requires -$O({{n^2 + n}\over 2})$ work. In standard big-O notation these would be said to be equivalent. However, in the -context of the this text the magnitude of the inputs will not approach an infinite size. This means the conventional limit -notation wisdom does not apply to the cancellation of constants. - -Throughout the discussions various ``work levels'' will be discussed. These levels are the $O(1)$, -$O(n)$, $O(n^2)$, ..., $O(n^k)$ work efforts. For example, operations at the $O(n^k)$ ``level'' are said to be -executed more frequently than operations at the $O(n^m)$ ``level'' when $k > m$. Obviously most optimizations will pay -off the most at the higher levels since they represent the bulk of the effort required. - -\section{Exercises} -Within the more advanced chapters a section will be set aside to give the reader some challenging exercises. These exercises are not -designed to be prize winning problems, but to be thought provoking. Wherever possible the problems are forward minded stating -problems that will be answered in subsequent chapters. The reader is encouraged to finish the exercises as they appear to get a -better understanding of the subject material. - -Similar to the exercises of \cite{TAOCPV2} as explained on pp.\textit{ix} these exercises are given a scoring system. However, unlike -\cite{TAOCPV2} the problems do not get nearly as hard as often. The scoring of these exercises ranges from one (\textit{the easiest}) to -five (\textit{the hardest}). The following table sumarizes the scoring. - -\vspace{5mm} -\begin{tabular}{cl} -$\left [ 1 \right ]$ & An easy problem that should only take the reader a manner of \\ - & minutes to solve. Usually does not involve much computer time. \\ - & \\ -$\left [ 2 \right ]$ & An easy problem that involves a marginal amount of computer \\ - & time usage. Usually requires a program to be written to \\ - & solve the problem. \\ - & \\ -$\left [ 3 \right ]$ & A moderately hard problem that requires a non-trivial amount \\ - & of work. Usually involves trivial research and development of \\ - & new theory from the perspective of a student. \\ - & \\ -$\left [ 4 \right ]$ & A moderately hard problem that involves a non-trivial amount \\ - & of work and research. The solution to which will demonstrate \\ - & a higher mastery of the subject matter. \\ - & \\ -$\left [ 5 \right ]$ & A hard problem that involves concepts that are non-trivial. \\ - & Solutions to these problems will demonstrate a complete mastery \\ - & of the given subject. \\ - & \\ -\end{tabular} - -Essentially problems at the first level are meant to be simple questions that the reader can answer quickly without programming a solution or -devising new theory. These problems are quick tests to see if the material is understood. Problems at the second level are also -designed to be easy but will require a program or algorithm to be implemented to arrive at the answer. - -Problems at the third level are meant to be a bit more difficult. Often the answer is fairly obvious but arriving at an exacting solution -requires some thought and skill. These problems will almost always involve devising a new algorithm or implementing a variation of -another algorithm. - -Problems at the fourth level are meant to be even more difficult as well as involve some research. The reader will most likely not know -the answer right away nor will this text provide the exact details of the answer (\textit{or at least not until a subsequent chapter}). Problems -at the fifth level are meant to be the hardest problems relative to all the other problems in the chapter. People who can correctly -answer fifth level problems have a mastery of the subject matter at hand. - -Often problems will be tied together. The purpose of this is to start a chain of thought that will be discussed in future chapters. The reader -is encouraged to answer the follow-up problems and try to draw the relevence of problems. - -\chapter{Introduction to LibTomMath} - -\section{What is LibTomMath?} -LibTomMath is a free and open source multiple precision library written in portable ISO C source code. By portable it is -meant that the library does not contain any code that is computer platform dependent or otherwise problematic to use on any -given platform. The library has been successfully tested under numerous operating systems including Solaris, MacOS, Windows, -Linux, PalmOS and on standalone hardware such as the Gameboy Advance. The library is designed to contain enough -functionality to be able to develop applications such as public key cryptosystems. - -\section{Goals of LibTomMath} - -Even though the library is written entirely in portable ISO C considerable care has been taken to -optimize the algorithm implementations within the library. Specifically the code has been written to work well with -the GNU C Compiler (\textit{GCC}) on both x86 and ARMv4 processors. Wherever possible highly efficient -algorithms (\textit{such as Karatsuba multiplication, sliding window exponentiation and Montgomery reduction}) have -been provided to make the library as efficient as possible. Even with the optimal and sometimes specialized -algorithms that have been included the Application Programing Interface (\textit{API}) has been kept as simple as possible. -Often generic place holder routines will make use of specialized algorithms automatically without the developer's -attention. One such example is the generic multiplication algorithm \textbf{mp\_mul()} which will automatically use -Karatsuba multiplication if the inputs are of a specific size. - -Making LibTomMath as efficient as possible is not the only goal of the LibTomMath project. Ideally the library should -be source compatible with another popular library which makes it more attractive for developers to use. In this case the -MPI library was used as a API template for all the basic functions. - -The project is also meant to act as a learning tool for students. The logic being that no easy-to-follow ``bignum'' -library exists which can be used to teach computer science students how to perform fast and reliable multiple precision -arithmetic. To this end the source code has been given quite a few comments and algorithm discussion points. Often routines have -more comments than lines of code. - -\section{Choice of LibTomMath} -LibTomMath was chosen as the case study of this text not only because the author of both projects is one and the same but -for more worthy reasons. Other libraries such as GMP, MPI, LIP and OpenSSL have multiple precision -integer arithmetic routines but would not be ideal for this text for reasons as will be explained in the -following sub-sections. - -\subsection{Code Base} -The LibTomMath code base is all portable ISO C source code. This means that there are no platform dependent conditional -segments of code littered throughout the source. This clean and uncluttered approach to the library means that a -developer can more readily ascertain the true intent of a given section of source code without trying to keep track of -what conditional code will be used. - -The code base of LibTomMath is also well organized. Each function is in its own separate source code file -which allows the reader to find a given function very fast. When compiled with GCC for the x86 processor the entire -library is a mere 87,760 bytes (\textit{$116,182$ bytes for ARMv4 processors}). This includes every single function -LibTomMath provides from basic arithmetic to various number theoretic functions such as modular exponentiation, various -reduction algorithms and Jacobi symbol computation. - -By comparison MPI which has fewer functions than LibTomMath compiled with the same conditions is 45,429 bytes -(\textit{$54,536$ for ARMv4}). GMP which has rather large collection of functions with the default configuration on an -x86 Athlon is 2,950,688 bytes. Note that while LibTomMath has fewer functions than GMP it has been used as the sole basis -for several public key cryptosystems without having to seek additional outside functions to supplement the library. - -\subsection{API Simplicity} -LibTomMath is designed after the MPI library and shares the API design. Quite often programs that use MPI will build -with LibTomMath without change. The function names are relatively straight forward as to what they perform. Almost all of the -functions except for a few minor exceptions which as will be discussed are for good reasons share the same parameter passing -convention. The learning curve is fairly shallow with the API provided which is an extremely valuable benefit for the -student and developer alike. - -The LIP library is an example of a library with an API that is awkward to work with. LIP uses function names that are often ``compressed'' to -illegible short hand. LibTomMath does not share this fault. - -\subsection{Optimizations} -While LibTomMath is certainly not the fastest library (\textit{GMP often beats LibTomMath by a factor of two}) it does -feature a set of optimal algorithms for tasks ranging from modular reduction to squaring. GMP and LIP also feature -such optimizations while MPI only uses baseline algorithms with no optimizations. - -LibTomMath is almost always an order of magnitude faster than the MPI library at computationally expensive tasks such as modular -exponentiation. In the grand scheme of ``bignum'' libraries LibTomMath is faster than the average library and usually -slower than the best libraries such as GMP and OpenSSL by a small factor. - -\subsection{Portability and Stability} -LibTomMath will build ``out of the box'' on any platform equipped with a modern version of the GNU C Compiler -(\textit{GCC}). This means that without changes the library will build without configuration or setting up any -variables. LIP and MPI will build ``out of the box'' as well but have numerous known bugs. Most notably the author of -MPI is not working on his library anymore. - -GMP requires a configuration script to run and will not build out of the box. GMP and LibTomMath are still in active -development and are very stable across a variety of platforms. - -\subsection{Choice} -LibTomMath is a relatively compact, well documented, highly optimized and portable library which seems only natural for -the case study of this text. Various source files from the LibTomMath project will be included within the text. However, the -reader is encouraged to download their own copy of the library to actually be able to work with the library. - -\chapter{Getting Started} -MARK,BASICOP -\section{Library Basics} -To begin the design of a multiple precision integer library a primitive data type and a series of primitive algorithms must be established. A data -type that will hold the information required to maintain a multiple precision integer must be designed. With this basic data type of a series -of low level algorithms for initializing, clearing, growing and optimizing multiple precision integers can be developed to form the basis of -the entire library of algorithms. - -\section{What is a Multiple Precision Integer?} -Recall that most programming languages (\textit{in particular C}) only have fixed precision data types that on their own cannot be used -to represent values larger than their precision alone will allow. The purpose of multiple precision algorithms is to use these fixed precision -data types to create multiple precision integers which may represent values that are much larger. - -As a well known analogy, school children are taught how to form numbers larger than nine by prepending more radix ten digits. In the decimal system -the largest value is only $9$ since the digits may only have values from $0$ to $9$. However, by concatenating digits together larger numbers -may be represented. Computer based multiple precision arithmetic is essentially the same concept except with a different radix. - -What most people probably do not think about explicitly are the various other attributes that describe a multiple precision integer. For example, -the integer $154_{10}$ has two immediately obvious properties. First, the integer is positive, that is the sign of this particular integer -is positive as oppose to negative. Second, the integer has three digits in its representation. There is an additional property that the integer -posesses that does not concern pencil-and-paper arithmetic. The third property is how many digits are allowed for the integer. - -The human analogy of this third property is ensuring there is enough space on the paper to right the integer. Computers must maintain a -strict control on memory usage with respect to the digits of a multiple precision integer. These three properties make up what is known -as a multiple precision integer or mp\_int for short. - -\subsection{The mp\_int structure} -The mp\_int structure is the ISO C based manifestation of what represents a multiple precision integer. The ISO C standard does not provide for -any such data type but it does provide for making composite data types known as structures. The following is the structure definition -used within LibTomMath. - -\index{mp\_int} -\begin{verbatim} -typedef struct { - int used, alloc, sign; - mp_digit *dp; -} mp_int; -\end{verbatim} - -The mp\_int structure can be broken down as follows. - -\begin{enumerate} -\item The \textbf{used} parameter denotes how many digits of the array \textbf{dp} contain the digits used to represent -a given integer. The \textbf{used} count must not exceed the \textbf{alloc} count. - -\item The array \textbf{dp} holds the digits that represent the given integer. It is padded with $\textbf{alloc} - \textbf{used}$ zero -digits. - -\item The \textbf{alloc} parameter denotes how -many digits are available in the array to use by functions before it has to increase in size. When the \textbf{used} count -of a result would exceed the \textbf{alloc} count all of the algorithms will automatically increase the size of the -array to accommodate the precision of the result. - -\item The \textbf{sign} parameter denotes the sign as either zero/positive (\textbf{MP\_ZPOS}) or negative (\textbf{MP\_NEG}). -\end{enumerate} - -\section{Argument Passing} -A convention of argument passing must be adopted early on in the development of any library. Making the function prototypes -consistent will help eliminate many headaches in the future as the library grows to significant complexity. In LibTomMath the multiple precision -integer functions accept parameters from left to right as pointers to mp\_int structures. That means that the source operands are -placed on the left and the destination on the right. Consider the following examples. - -\begin{verbatim} - mp_mul(&a, &b, &c); /* c = a * b */ - mp_add(&a, &b, &a); /* a = a + b */ - mp_sqr(&a, &b); /* b = a * a */ -\end{verbatim} - -The left to right order is a fairly natural way to implement the functions since it lets the developer read aloud the -functions and make sense of them. For example, the first function would read ``multiply a and b and store in c''. - -Certain libraries (\textit{LIP by Lenstra for instance}) accept parameters the other way around. That is the destination -on the left and arguments on the right. In truth it is entirely a matter of preference. In the case of LibTomMath the -convention from the MPI library has been adopted. - -Another very useful design consideration is whether to allow argument sources to also be a destination. For example, the -second example (\textit{mp\_add}) adds $a$ to $b$ and stores in $a$. This is an important feature to implement since it -allows the higher up functions to cut down on the number of variables. However, to implement this feature specific -care has to be given to ensure the destination is not modified before the source is fully read. - -\section{Return Values} -A well implemented library, no matter what its purpose, should trap as many runtime errors as possible and return them to the -caller. By catching runtime errors a library can be guaranteed to prevent undefined behaviour. In a multiple precision -library the only errors that can occur occur are related to inappropriate inputs (\textit{division by zero for instance}) or -memory allocation errors. - -In LibTomMath any function that can cause a runtime error will return an error as an \textbf{int} data type with one of the -following values. - -\index{MP\_OKAY} \index{MP\_VAL} \index{MP\_MEM} -\begin{center} -\begin{tabular}{|l|l|} -\hline \textbf{Value} & \textbf{Meaning} \\ -\hline \textbf{MP\_OKAY} & The function was successful \\ -\hline \textbf{MP\_VAL} & One of the input value(s) was invalid \\ -\hline \textbf{MP\_MEM} & The function ran out of heap memory \\ -\hline -\end{tabular} -\end{center} - -When an error is detected within a function it should free any memory it allocated and return as soon as possible. The goal -is to leave the system in the same state the system was when the function was called. Error checking with this style of API is fairly simple. - -\begin{verbatim} - int err; - if ((err = mp_add(&a, &b, &c)) != MP_OKAY) { - printf("Error: %d\n", err); - exit(EXIT_FAILURE); - } -\end{verbatim} - -The GMP library uses C style \textit{signals} to flag errors which is of questionable use. Not all errors are fatal -and it was not deemed ideal by the author of LibTomMath to force developers to have signal handlers for such cases. - -\section{Initialization and Clearing} -The logical starting point when actually writing multiple precision integer functions is the initialization and -clearing of the integers. These two functions will be used by far the most throughout the algorithms whenever -temporary integers are required. - -Given the basic mp\_int structure an initialization routine must first allocate memory to hold the digits of -the integer. Often it is optimal to allocate a sufficiently large pre-set number of digits even considering -the initial integer will represent zero. If only a single digit were allocated quite a few re-allocations -would occur for the majority of inputs. There is a tradeoff between how many default digits to allocate -and how many re-allocations are tolerable. - -If the memory for the digits has been successfully allocated then the rest of the members of the structure must -be initialized. Since the initial state is to represent a zero integer the digits allocated must all be zeroed. The -\textbf{used} count set to zero and \textbf{sign} set to \textbf{MP\_ZPOS}. - -\subsection{Initializing an mp\_int} -To initialize an mp\_int the mp\_init algorithm shall be used. The purpose of this algorithm is to allocate -the memory required and initialize the integer to a default representation of zero. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_init}. \\ -\textbf{Input}. An mp\_int $a$ \\ -\textbf{Output}. Allocate memory for the digits and set to a zero state. \\ -\hline \\ -1. Allocate memory for \textbf{MP\_PREC} digits. \\ -2. If the allocation failed then return(\textit{MP\_MEM}) \\ -3. for $n$ from $0$ to $MP\_PREC - 1$ do \\ -\hspace{3mm}3.1 $a_n \leftarrow 0$\\ -4. $a.sign \leftarrow MP\_ZPOS$\\ -5. $a.used \leftarrow 0$\\ -6. $a.alloc \leftarrow MP\_PREC$\\ -7. Return(\textit{MP\_OKAY})\\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_init} -\end{figure} - -\textbf{Algorithm mp\_init.} -The \textbf{MP\_PREC} variable is a simple constant used to dictate minimal precision of allocated integers. It is ideally at least equal to $32$ but -can be any reasonable power of two. Steps one and two allocate the memory and account for it. If the allocation fails the algorithm returns -immediately to signal the failure. Step three will ensure that all the digits are in the default state of zero. Finally steps -four through six set the default settings of the \textbf{sign}, \textbf{used} and \textbf{alloc} members of the mp\_int structure. - -EXAM,bn_mp_init.c - -The \textbf{OPT\_CAST} type cast on line @22,OPT_CAST@ is designed to allow C++ compilers to build the code out of -the box. Microsoft C V5.00 is known to cause problems without the cast. Also note that if the memory -allocation fails the other members of the mp\_int will be in an undefined state. The code from -line @29,a->used@ to line @31,a->sign@ sets the default state for a mp\_int which is zero, positive and no used digits. - -\subsection{Clearing an mp\_int} -When an mp\_int is no longer required the memory allocated for it can be cleared from the heap with -the mp\_clear algorithm. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_clear}. \\ -\textbf{Input}. An mp\_int $a$ \\ -\textbf{Output}. The memory for $a$ is cleared. \\ -\hline \\ -1. If $a$ has been previously freed then return(\textit{MP\_OKAY}). \\ -2. Free the digits of $a$ and mark $a$ as freed. \\ -3. $a.used \leftarrow 0$ \\ -4. $a.alloc \leftarrow 0$ \\ -5. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_clear} -\end{figure} - -\textbf{Algorithm mp\_clear.} -In steps one and two the memory for the digits are only free'd if they had not been previously released before. -This is more of concern for the implementation since it is used to prevent ``double-free'' errors. It also helps catch -code errors where mp\_ints are used after being cleared. Similarly steps three and four set the -\textbf{used} and \textbf{alloc} to known values which would be easy to spot during debugging. For example, if an mp\_int is expected -to be non-zero and its \textbf{used} member is observed to be zero (\textit{due to being cleared}) then an obvious bug in the code has been -spotted. - -EXAM,bn_mp_clear.c - -The \textbf{if} statement on line @21,a->dp != NULL@ prevents the heap from being corrupted if a user double-frees an -mp\_int. For example, a trivial case of this bug would be as follows. - -\begin{verbatim} -mp_int a; -mp_init(&a); -mp_clear(&a); -mp_clear(&a); -\end{verbatim} - -Without that check the code would try to free the memory allocated for the digits twice which will cause most standard C -libraries to cause a fault. Also by setting the pointer to \textbf{NULL} it helps debug code that may inadvertently -free the mp\_int before it is truly not needed. The allocated digits are set to zero before being freed on line @24,memset@. -This is ideal for cryptographic situations where the mp\_int is a secret parameter. - -The following snippet is an example of using both the init and clear functions. - -\begin{small} -\begin{verbatim} -#include -#include -#include -int main(void) -{ - mp_int num; - int err; - - /* init the bignum */ - if ((err = mp_init(&num)) != MP_OKAY) { - printf("Error: %d\n", err); - return EXIT_FAILURE; - } - - /* do work with it ... */ - - /* clear up */ - mp_clear(&num); - - return EXIT_SUCCESS; -} -\end{verbatim} -\end{small} - -\section{Other Initialization Routines} - -It is often helpful to have specialized initialization algorithms to simplify the design of other algorithms. For example, an -initialization followed by a copy is a common operation when temporary copies of integers are required. It is quite -beneficial to have a series of simple helper functions available. - -\subsection{Initializing Variable Sized mp\_int Structures} -Occasionally the number of digits required will be known in advance of an initialization. In these -cases the mp\_init\_size algorithm can be of use. The purpose of this algorithm is similar to mp\_init except that -it will allocate \textit{at least} a specified number of digits. This is ideal to prevent re-allocations when the -input size is known. - -\newpage\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_init\_size}. \\ -\textbf{Input}. An mp\_int $a$ and the requested number of digits $b$\\ -\textbf{Output}. $a$ is initialized to hold at least $b$ digits. \\ -\hline \\ -1. $u \leftarrow b\mbox{ (mod }MP\_PREC\mbox{)}$ \\ -2. $v \leftarrow b + 2 \cdot MP\_PREC - u$ \\ -3. Allocate $v$ digits. \\ -4. If the allocation failed then return(\textit{MP\_MEM}). \\ -5. for $n$ from $0$ to $v - 1$ do \\ -\hspace{3mm}5.1 $a_n \leftarrow 0$ \\ -6. $a.sign \leftarrow MP\_ZPOS$\\ -7. $a.used \leftarrow 0$\\ -8. $a.alloc \leftarrow v$\\ -9. Return(\textit{MP\_OKAY})\\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_init\_size} -\end{figure} - -\textbf{Algorithm mp\_init\_size.} -The value of $v$ is calculated to be at least the requested amount of digits $b$ plus additional padding. The padding is calculated -to be at least \textbf{MP\_PREC} digits plus enough digits to make the digit count a multiple of \textbf{MP\_PREC}. This padding is used to -prevent trivial allocations from becoming a bottleneck in the rest of the algorithms that depend on this. - -EXAM,bn_mp_init_size.c - -Line @23,MP_PREC@ will ensure that the number of digits actually allocated is padded up to the next multiple of -\textbf{MP\_PREC} plus an additional \textbf{MP\_PREC}. This ensures that the number of allocated digit is -always greater than the amount requested. As a result it prevents many trivial memory allocations. The value of -\textbf{MP\_PREC} is defined in ``tommath.h'' and must be a power of two. - -\subsection{Creating a Clone} -Another common sequence of operations is to make a local temporary copy of an argument. To initialize then copy a mp\_int will be known as -creating a clone. This is useful within functions that need to modify an integer argument but do not wish to actually modify the original copy. -The mp\_init\_copy algorithm will perform this very task. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_init\_copy}. \\ -\textbf{Input}. An mp\_int $a$ and $b$\\ -\textbf{Output}. $a$ is initialized to be a copy of $b$. \\ -\hline \\ -1. Init $a$. (\textit{mp\_init}) \\ -2. If the init of $a$ was unsuccessful return(\textit{MP\_MEM}) \\ -3. Copy $b$ to $a$. (\textit{mp\_copy}) \\ -4. Return the status of the copy operation. \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_init\_copy} -\end{figure} - -\textbf{Algorithm mp\_init\_copy.} -This algorithm will initialize a mp\_int variable and copy another previously initialized mp\_int variable into it. The algorithm will -detect when the initialization fails and returns the error to the calling algorithm. As such this algorithm will perform two operations -in one step. - -EXAM,bn_mp_init_copy.c - -This will initialize \textbf{a} and make it a verbatim copy of the contents of \textbf{b}. Note that -\textbf{a} will have its own memory allocated which means that \textbf{b} may be cleared after the call -and \textbf{a} will be left intact. - -\subsection{Multiple Integer Initializations And Clearings} -Occasionally a function will require a series of mp\_int data types to be made available. The mp\_init\_multi algorithm -is provided to simplify such cases. The purpose of this algorithm is to initialize a variable length array of mp\_int -structures at once. As a result algorithms that require multiple integers only has to use -one algorithm to initialize all the mp\_int variables. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_init\_multi}. \\ -\textbf{Input}. Variable length array of mp\_int variables of length $k$. \\ -\textbf{Output}. The array is initialized such that each each mp\_int is ready to use. \\ -\hline \\ -1. for $n$ from 0 to $k - 1$ do \\ -\hspace{+3mm}1.1. Initialize the $n$'th mp\_int (\textit{mp\_init}) \\ -\hspace{+3mm}1.2. If initialization failed then do \\ -\hspace{+6mm}1.2.1. for $j$ from $0$ to $n$ do \\ -\hspace{+9mm}1.2.1.1. Free the $j$'th mp\_int (\textit{mp\_clear}) \\ -\hspace{+6mm}1.2.2. Return(\textit{MP\_MEM}) \\ -2. Return(\textit{MP\_OKAY}) \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_init\_multi} -\end{figure} - -\textbf{Algorithm mp\_init\_multi.} -The algorithm will initialize the array of mp\_int variables one at a time. As soon as an runtime error is detected (\textit{step 1.2}) all of -the previously initialized variables are cleared. The goal is an ``all or nothing'' initialization which allows for quick recovery from runtime -errors. - -Similarly to clear a variable length array of mp\_int structures the mp\_clear\_multi algorithm will be used. - -Consider the following snippet which demonstrates how to use both routines. -\begin{small} -\begin{verbatim} -#include -#include -#include -int main(void) -{ - mp_int num1, num2, num3; - int err; - - if ((err = mp_init_multi(&num1, &num2, &num3, NULL)) !- MP_OKAY) { - printf("Error: %d\n", err); - return EXIT_FAILURE; - } - - /* at this point num1/num2/num3 are ready */ - - /* free them */ - mp_clear_multi(&num1, &num2, &num3, NULL); - - return EXIT_SUCCESS; -} -\end{verbatim} -\end{small} - -Note how both lists are terminated with the \textbf{NULL} variable. This indicates to the algorithms to stop fetching parameters off -of the stack. If it is not present the functions will most likely cause a segmentation fault. - -EXAM,bn_mp_multi.c - -Both routines are implemented in the same source file since they are typically used in conjunction with each other. - -\section{Maintenance} -A small useful collection of mp\_int maintenance functions will also prove useful. - -\subsection{Augmenting Integer Precision} -When storing a value in an mp\_int sufficient digits must be available to accomodate the entire value without -loss of precision. Quite often the size of the array given by the \textbf{alloc} member is large enough to simply -increase the \textbf{used} digit count. However, when the size of the array is too small it must be re-sized -appropriately to accomodate the result. The mp\_grow algorithm will provide this functionality. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_grow}. \\ -\textbf{Input}. An mp\_int $a$ and an integer $b$. \\ -\textbf{Output}. $a$ is expanded to accomodate $b$ digits. \\ -\hline \\ -1. if $a.alloc \ge b$ then return(\textit{MP\_OKAY}) \\ -2. $u \leftarrow b\mbox{ (mod }MP\_PREC\mbox{)}$ \\ -3. $v \leftarrow b + 2 \cdot MP\_PREC - u$ \\ -4. Re-Allocate the array of digits $a$ to size $v$ \\ -5. If the allocation failed then return(\textit{MP\_MEM}). \\ -6. for n from a.alloc to $v - 1$ do \\ -\hspace{+3mm}6.1 $a_n \leftarrow 0$ \\ -7. $a.alloc \leftarrow v$ \\ -8. Return(\textit{MP\_OKAY}) \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_grow} -\end{figure} - -\textbf{Algorithm mp\_grow.} -Step one will prevent a re-allocation from being performed if it was not required. This is useful to prevent mp\_ints -from growing excessively in code that erroneously calls mp\_grow. Similar to mp\_init\_size the requested digit count -is padded to provide more digits than requested. - -In step four it is assumed that the reallocation leaves the lower $a.alloc$ digits intact. This is much akin to how the -\textit{realloc} function from the standard C library works. Since the newly allocated digits are assumed to contain -undefined values they are also initially zeroed. - -EXAM,bn_mp_grow.c - -The first step is to see if we actually need to perform a re-allocation at all. This is tested for on line -@24,a->alloc < size@. Similar to mp\_init\_size the same code on line @26,MP_PREC - 1@ was used to resize the -digits requested. A simple for loop from line @34,a->alloc@ to line @38,}@ will zero all digits that were above the -old \textbf{alloc} limit to make sure the integer is in a known state. - -\subsection{Clamping Excess Digits} -When a function anticipates a result will be $n$ digits it is simpler to assume this is true within the body of -the function. For example, a multiplication of a $i$ digit number by a $j$ digit produces a result of at most -$i + j$ digits. It is entirely possible that the result is $i + j - 1$ though, with no final carry into the last -position. However, suppose the destination had to be first expanded (\textit{via mp\_grow}) to accomodate $i + j - 1$ -digits than further expanded to accomodate the final carry. That would be a considerable waste of time since heap -operations are relatively slow. - -The ideal solution is to always assume the result is $i + j$ and fix up the \textbf{used} count after the function -terminates. This way a single heap operation (\textit{at most}) is required. However, if the result was not checked -there would be an excess high order zero digit. - -For example, suppose the product of two integers was $x_n = (0x_{n-1}x_{n-2}...x_0)_{\beta}$. The leading zero digit -will not contribute to the precision of the result. In fact, through subsequent operations more leading zero digits would -accumulate to the point the size of the integer would be prohibitive. As a result even though the precision is very -low the representation is excessively large. - -The mp\_clamp algorithm is designed to solve this very problem. It will trim leading zeros by decrementing the -\textbf{used} count until a non-zero leading digit is found. Also in this system, zero is considered to be a positive -number which means that if the \textbf{used} count is decremented to zero the sign must be set to \textbf{MP\_ZPOS}. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_clamp}. \\ -\textbf{Input}. An mp\_int $a$ \\ -\textbf{Output}. Any excess leading zero digits of $a$ are removed \\ -\hline \\ -1. while $a.used > 0$ and $a_{a.used - 1} = 0$ do \\ -\hspace{+3mm}1.1 $a.used \leftarrow a.used - 1$ \\ -2. if $a.used = 0$ then do \\ -\hspace{+3mm}2.1 $a.sign \leftarrow MP\_ZPOS$ \\ -\hline \\ -\end{tabular} -\end{center} -\caption{Algorithm mp\_clamp} -\end{figure} - -\textbf{Algorithm mp\_clamp.} -As can be expected this algorithm is very simple. The loop on step one is expected to iterate only once or twice at -the most. For example, this will happen in cases where there is not a carry to fill the last position. Step two fixes the sign for -when all of the digits are zero to ensure that the mp\_int is valid at all times. - -EXAM,bn_mp_clamp.c - -Note on line @27,while@ how to test for the \textbf{used} count is made on the left of the \&\& operator. In the C programming -language the terms to \&\& are evaluated left to right with a boolean short-circuit if any condition fails. This is -important since if the \textbf{used} is zero the test on the right would fetch below the array. That is obviously -undesirable. The parenthesis on line @28,a->used@ is used to make sure the \textbf{used} count is decremented and not -the pointer ``a''. - -\section*{Exercises} -\begin{tabular}{cl} -$\left [ 1 \right ]$ & Discuss the relevance of the \textbf{used} member of the mp\_int structure. \\ - & \\ -$\left [ 1 \right ]$ & Discuss the consequences of not using padding when performing allocations. \\ - & \\ -$\left [ 2 \right ]$ & Estimate an ideal value for \textbf{MP\_PREC} when performing 1024-bit RSA \\ - & encryption when $\beta = 2^{28}$. \\ - & \\ -$\left [ 1 \right ]$ & Discuss the relevance of the algorithm mp\_clamp. What does it prevent? \\ - & \\ -$\left [ 1 \right ]$ & Give an example of when the algorithm mp\_init\_copy might be useful. \\ - & \\ -\end{tabular} - - -\chapter{Basic Operations} -\section{Copying an Integer} -After the various house-keeping routines are in place, simple algorithms can be designed to take advantage of them. Being able -to make a verbatim copy of an integer is a very useful function to have. To copy an integer the mp\_copy algorithm will be used. - -\newpage\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_copy}. \\ -\textbf{Input}. An mp\_int $a$ and $b$. \\ -\textbf{Output}. Store a copy of $a$ in $b$. \\ -\hline \\ -1. Check if $a$ and $b$ point to the same location in memory. \\ -2. If true then return(\textit{MP\_OKAY}). \\ -3. If $b.alloc < a.used$ then grow $b$ to $a.used$ digits. (\textit{mp\_grow}) \\ -4. If failed to grow then return(\textit{MP\_MEM}). \\ -5. for $n$ from 0 to $a.used - 1$ do \\ -\hspace{3mm}5.1 $b_{n} \leftarrow a_{n}$ \\ -6. if $a.used < b.used - 1$ then \\ -\hspace{3mm}6.1. for $n$ from $a.used$ to $b.used - 1$ do \\ -\hspace{6mm}6.1.1 $b_{n} \leftarrow 0$ \\ -7. $b.used \leftarrow a.used$ \\ -8. $b.sign \leftarrow a.sign$ \\ -9. return(\textit{MP\_OKAY}) \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_copy} -\end{figure} - -\textbf{Algorithm mp\_copy.} -Step 1 and 2 make sure that the two mp\_ints are unique. This allows the user to call the copy function with -potentially the same input and not waste time. Step 3 and 4 ensure that the destination is large enough to -hold a copy of the input $a$. Note that the \textbf{used} member of $b$ may be smaller than the \textbf{used} -member of $a$ but a memory re-allocation is only required if the \textbf{alloc} member of $b$ is smaller. This -prevents trivial memory reallocations. - -Step 5 copies the digits from $a$ to $b$ while step 6 ensures that if initially $\vert b \vert > \vert a \vert$, -the more significant digits of $b$ will be zeroed. Finally steps 7 and 8 copies the \textbf{used} and \textbf{sign} members over -which completes the copy operation. - -EXAM,bn_mp_copy.c - -Source lines @23,if dst ==@-@31,}@ do the initial house keeping. That is to see if the input is unique and if so to -make sure there is enough room. If not enough space is available it returns the error and leaves the destination variable -intact. - -The inner loop of the copy operation is contained between lines @34,{@ and @50,}@. Many LibTomMath routines are designed with this source code style -in mind, making aliases to shorten lengthy pointers (\textit{see line @38,->@ and @39,->@}) for rapid use. Also the -use of nested braces creates a simple way to denote various portions of code that reside on various work levels. Here, the copy loop is at the -$O(n)$ level. - -\section{Zeroing an Integer} -Reseting an mp\_int to the default state is a common step in many algorithms. The mp\_zero algorithm will be the algorithm used to -perform this task. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_zero}. \\ -\textbf{Input}. An mp\_int $a$ \\ -\textbf{Output}. Zero the contents of $a$ \\ -\hline \\ -1. $a.used \leftarrow 0$ \\ -2. $a.sign \leftarrow$ MP\_ZPOS \\ -3. for $n$ from 0 to $a.alloc - 1$ do \\ -\hspace{3mm}3.1 $a_n \leftarrow 0$ \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_zero} -\end{figure} - -\textbf{Algorithm mp\_zero.} -This algorithm simply resets a mp\_int to the default state. - -EXAM,bn_mp_zero.c - -After the function is completed, all of the digits are zeroed, the \textbf{used} count is zeroed and the -\textbf{sign} variable is set to \textbf{MP\_ZPOS}. - -\section{Sign Manipulation} -\subsection{Absolute Value} -With the mp\_int representation of an integer, calculating the absolute value is trivial. The mp\_abs algorithm will compute -the absolute value of an mp\_int. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_abs}. \\ -\textbf{Input}. An mp\_int $a$ \\ -\textbf{Output}. Computes $b = \vert a \vert$ \\ -\hline \\ -1. Copy $a$ to $b$. (\textit{mp\_copy}) \\ -2. If the copy failed return(\textit{MP\_MEM}). \\ -3. $b.sign \leftarrow MP\_ZPOS$ \\ -4. Return(\textit{MP\_OKAY}) \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_abs} -\end{figure} - -\textbf{Algorithm mp\_abs.} -This algorithm computes the absolute of an mp\_int input. As can be expected the algorithm is very trivial. - -EXAM,bn_mp_abs.c - -\subsection{Integer Negation} -With the mp\_int representation of an integer, calculating the negation is also trivial. The mp\_neg algorithm will compute -the negative of an mp\_int input. - -\newpage\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_neg}. \\ -\textbf{Input}. An mp\_int $a$ \\ -\textbf{Output}. Computes $b = -a$ \\ -\hline \\ -1. Copy $a$ to $b$. (\textit{mp\_copy}) \\ -2. If the copy failed return(\textit{MP\_MEM}). \\ -3. If $a.sign = MP\_ZPOS$ then do \\ -\hspace{3mm}3.1 $b.sign = MP\_NEG$. \\ -4. else do \\ -\hspace{3mm}4.1 $b.sign = MP\_ZPOS$. \\ -5. Return(\textit{MP\_OKAY}) \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_neg} -\end{figure} - -\textbf{Algorithm mp\_neg.} -This algorithm computes the negation of an input. - -EXAM,bn_mp_neg.c - -\section{Small Constants} -\subsection{Setting Small Constants} -Often a mp\_int must be set to a relatively small value such as $1$ or $2$. For these cases the mp\_set algorithm is useful. - -\newpage\begin{figure} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_set}. \\ -\textbf{Input}. An mp\_int $a$ and a digit $b$ \\ -\textbf{Output}. Make $a$ equivalent to $b$ \\ -\hline \\ -1. Zero $a$ (\textit{mp\_zero}). \\ -2. $a_0 \leftarrow b \mbox{ (mod }\beta\mbox{)}$ \\ -3. $a.used \leftarrow \left \lbrace \begin{array}{ll} - 1 & \mbox{if }a_0 > 0 \\ - 0 & \mbox{if }a_0 = 0 - \end{array} \right .$ \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_set} -\end{figure} - -\textbf{Algorithm mp\_set.} -This algorithm sets a mp\_int to a small single digit value. Step number 1 ensures that the integer is reset to the default state. The -single digit is set (\textit{modulo $\beta$}) and the \textbf{used} count is adjusted accordingly. - -EXAM,bn_mp_set.c - -Line @21,mp_zero@ calls mp\_zero() to clear the mp\_int and reset the sign. Line @22,MP_MASK@ copies the digit -into the least significant location. Note the usage of a new constant \textbf{MP\_MASK}. This constant is used to quickly -reduce an integer modulo $\beta$. Since $\beta$ is of the form $2^k$ for any suitable $k$ it suffices to perform a binary AND with -$MP\_MASK = 2^k - 1$ to perform the reduction. Finally line @23,a->used@ will set the \textbf{used} member with respect to the -digit actually set. This function will always make the integer positive. - -One important limitation of this function is that it will only set one digit. The size of a digit is not fixed, meaning source that uses -this function should take that into account. Meaning that only trivially small constants can be set using this function. - -\subsection{Setting Large Constants} -To overcome the limitations of the mp\_set algorithm the mp\_set\_int algorithm is provided. It accepts a ``long'' -data type as input and will always treat it as a 32-bit integer. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_set\_int}. \\ -\textbf{Input}. An mp\_int $a$ and a ``long'' integer $b$ \\ -\textbf{Output}. Make $a$ equivalent to $b$ \\ -\hline \\ -1. Zero $a$ (\textit{mp\_zero}) \\ -2. for $n$ from 0 to 7 do \\ -\hspace{3mm}2.1 $a \leftarrow a \cdot 16$ (\textit{mp\_mul2d}) \\ -\hspace{3mm}2.2 $u \leftarrow \lfloor b / 2^{4(7 - n)} \rfloor \mbox{ (mod }16\mbox{)}$\\ -\hspace{3mm}2.3 $a_0 \leftarrow a_0 + u$ \\ -\hspace{3mm}2.4 $a.used \leftarrow a.used + 1$ \\ -3. Clamp excess used digits (\textit{mp\_clamp}) \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_set\_int} -\end{figure} - -\textbf{Algorithm mp\_set\_int.} -The algorithm performs eight iterations of a simple loop where in each iteration four bits from the source are added to the -mp\_int. Step 2.1 will multiply the current result by sixteen making room for four more bits in the less significant positions. In step 2.2 the -next four bits from the source are extracted and are added to the mp\_int. The \textbf{used} digit count is -incremented to reflect the addition. The \textbf{used} digit counter is incremented since if any of the leading digits were zero the mp\_int would have -zero digits used and the newly added four bits would be ignored. - -Excess zero digits are trimmed in steps 2.1 and 3 by using higher level algorithms mp\_mul2d and mp\_clamp. - -EXAM,bn_mp_set_int.c - -This function sets four bits of the number at a time to handle all practical \textbf{DIGIT\_BIT} sizes. The weird -addition on line @38,a->used@ ensures that the newly added in bits are added to the number of digits. While it may not -seem obvious as to why the digit counter does not grow exceedingly large it is because of the shift on line @27,mp_mul_2d@ -as well as the call to mp\_clamp() on line @40,mp_clamp@. Both functions will clamp excess leading digits which keeps -the number of used digits low. - -\section{Comparisons} -\subsection{Unsigned Comparisions} -Comparing a multiple precision integer is performed with the exact same algorithm used to compare two decimal numbers. For example, -to compare $1,234$ to $1,264$ the digits are extracted by their positions. That is we compare $1 \cdot 10^3 + 2 \cdot 10^2 + 3 \cdot 10^1 + 4 \cdot 10^0$ -to $1 \cdot 10^3 + 2 \cdot 10^2 + 6 \cdot 10^1 + 4 \cdot 10^0$ by comparing single digits at a time starting with the highest magnitude -positions. If any leading digit of one integer is greater than a digit in the same position of another integer then obviously it must be greater. - -The first comparision routine that will be developed is the unsigned magnitude compare which will perform a comparison based on the digits of two -mp\_int variables alone. It will ignore the sign of the two inputs. Such a function is useful when an absolute comparison is required or if the -signs are known to agree in advance. - -To facilitate working with the results of the comparison functions three constants are required. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{|r|l|} -\hline \textbf{Constant} & \textbf{Meaning} \\ -\hline \textbf{MP\_GT} & Greater Than \\ -\hline \textbf{MP\_EQ} & Equal To \\ -\hline \textbf{MP\_LT} & Less Than \\ -\hline -\end{tabular} -\end{center} -\caption{Comparison Return Codes} -\end{figure} - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_cmp\_mag}. \\ -\textbf{Input}. Two mp\_ints $a$ and $b$. \\ -\textbf{Output}. Unsigned comparison results ($a$ to the left of $b$). \\ -\hline \\ -1. If $a.used > b.used$ then return(\textit{MP\_GT}) \\ -2. If $a.used < b.used$ then return(\textit{MP\_LT}) \\ -3. for n from $a.used - 1$ to 0 do \\ -\hspace{+3mm}3.1 if $a_n > b_n$ then return(\textit{MP\_GT}) \\ -\hspace{+3mm}3.2 if $a_n < b_n$ then return(\textit{MP\_LT}) \\ -4. Return(\textit{MP\_EQ}) \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_cmp\_mag} -\end{figure} - -\textbf{Algorithm mp\_cmp\_mag.} -By saying ``$a$ to the left of $b$'' it is meant that the comparison is with respect to $a$, that is if $a$ is greater than $b$ it will return -\textbf{MP\_GT} and similar with respect to when $a = b$ and $a < b$. The first two steps compare the number of digits used in both $a$ and $b$. -Obviously if the digit counts differ there would be an imaginary zero digit in the smaller number where the leading digit of the larger number is. -If both have the same number of digits than the actual digits themselves must be compared starting at the leading digit. - -By step three both inputs must have the same number of digits so its safe to start from either $a.used - 1$ or $b.used - 1$ and count down to -the zero'th digit. If after all of the digits have been compared, no difference is found, the algorithm returns \textbf{MP\_EQ}. - -EXAM,bn_mp_cmp_mag.c - -The two if statements on lines @24,if@ and @28,if@ compare the number of digits in the two inputs. These two are performed before all of the digits -are compared since it is a very cheap test to perform and can potentially save considerable time. The implementation given is also not valid -without those two statements. $b.alloc$ may be smaller than $a.used$, meaning that undefined values will be read from $b$ past the end of the -array of digits. - -\subsection{Signed Comparisons} -Comparing with sign considerations is also fairly critical in several routines (\textit{division for example}). Based on an unsigned magnitude -comparison a trivial signed comparison algorithm can be written. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_cmp}. \\ -\textbf{Input}. Two mp\_ints $a$ and $b$ \\ -\textbf{Output}. Signed Comparison Results ($a$ to the left of $b$) \\ -\hline \\ -1. if $a.sign = MP\_NEG$ and $b.sign = MP\_ZPOS$ then return(\textit{MP\_LT}) \\ -2. if $a.sign = MP\_ZPOS$ and $b.sign = MP\_NEG$ then return(\textit{MP\_GT}) \\ -3. if $a.sign = MP\_NEG$ then \\ -\hspace{+3mm}3.1 Return the unsigned comparison of $b$ and $a$ (\textit{mp\_cmp\_mag}) \\ -4 Otherwise \\ -\hspace{+3mm}4.1 Return the unsigned comparison of $a$ and $b$ \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_cmp} -\end{figure} - -\textbf{Algorithm mp\_cmp.} -The first two steps compare the signs of the two inputs. If the signs do not agree then it can return right away with the appropriate -comparison code. When the signs are equal the digits of the inputs must be compared to determine the correct result. In step -three the unsigned comparision flips the order of the arguments since they are both negative. For instance, if $-a > -b$ then -$\vert a \vert < \vert b \vert$. Step number four will compare the two when they are both positive. - -EXAM,bn_mp_cmp.c - -The two if statements on lines @22,if@ and @26,if@ perform the initial sign comparison. If the signs are not the equal then which ever -has the positive sign is larger. At line @30,if@, the inputs are compared based on magnitudes. If the signs were both negative then -the unsigned comparison is performed in the opposite direction (\textit{line @31,mp_cmp_mag@}). Otherwise, the signs are assumed to -be both positive and a forward direction unsigned comparison is performed. - -\section*{Exercises} -\begin{tabular}{cl} -$\left [ 2 \right ]$ & Modify algorithm mp\_set\_int to accept as input a variable length array of bits. \\ - & \\ -$\left [ 3 \right ]$ & Give the probability that algorithm mp\_cmp\_mag will have to compare $k$ digits \\ - & of two random digits (of equal magnitude) before a difference is found. \\ - & \\ -$\left [ 1 \right ]$ & Suggest a simple method to speed up the implementation of mp\_cmp\_mag based \\ - & on the observations made in the previous problem. \\ - & -\end{tabular} - -\chapter{Basic Arithmetic} -\section{Building Blocks} -At this point algorithms for initialization, clearing, zeroing, copying, comparing and setting small constants have been -established. The next logical set of algorithms to develop are addition, subtraction and digit shifting algorithms. These -algorithms make use of the lower level algorithms and are the cruicial building block for the multiplication algorithms. It is very important -that these algorithms are highly optimized. On their own they are simple $O(n)$ algorithms but they can be called from higher level algorithms -which easily places them at $O(n^2)$ or even $O(n^3)$ work levels. - -MARK,SHIFTS -All nine algorithms within this chapter make use of the logical bit shift operations denoted by $<<$ and $>>$ for left and right -logical shifts respectively. A logical shift is analogous to sliding the decimal point of radix-10 representations. For example, the real -number $0.9345$ is equivalent to $93.45\%$ which is found by sliding the the decimal two places to the right (\textit{multiplying by $10^2$}). -Mathematically a logical shift is equivalent to a division or multiplication by a power of two. -For example, $a << k = a \cdot 2^k$ while $a >> k = \lfloor a/2^k \rfloor$. - -One significant difference between a logical shift and the way decimals are shifted is that digits below the zero'th position are removed -from the number. For example, consider $1101_2 >> 1$ using decimal notation this would produce $110.1_2$. However, with a logical shift the -result is $110_2$. - -\section{Addition and Subtraction} -In normal fixed precision arithmetic negative numbers are easily represented by subtraction from the modulus. For example, with 32-bit integers -$a - b\mbox{ (mod }2^{32}\mbox{)}$ is the same as $a + (2^{32} - b) \mbox{ (mod }2^{32}\mbox{)}$ since $2^{32} \equiv 0 \mbox{ (mod }2^{32}\mbox{)}$. -As a result subtraction can be performed with a trivial series of logical operations and an addition. - -However, in multiple precision arithmetic negative numbers are not represented in the same way. Instead a sign flag is used to keep track of the -sign of the integer. As a result signed addition and subtraction are actually implemented as conditional usage of lower level addition or -subtraction algorithms with the sign fixed up appropriately. - -The lower level algorithms will add or subtract integers without regard to the sign flag. That is they will add or subtract the magnitude of -the integers respectively. - -\subsection{Low Level Addition} -An unsigned addition of multiple precision integers is performed with the same long-hand algorithm used to add decimal numbers. That is to add the -trailing digits first and propagate the resulting carry upwards. Since this is a lower level algorithm the name will have a ``s\_'' prefix. -Historically that convention stems from the MPI library where ``s\_'' stood for static functions that were hidden from the developer entirely. - -\newpage -\begin{figure}[!here] -\begin{center} -\begin{small} -\begin{tabular}{l} -\hline Algorithm \textbf{s\_mp\_add}. \\ -\textbf{Input}. Two mp\_ints $a$ and $b$ \\ -\textbf{Output}. The unsigned addition $c = \vert a \vert + \vert b \vert$. \\ -\hline \\ -1. if $a.used > b.used$ then \\ -\hspace{+3mm}1.1 $min \leftarrow b.used$ \\ -\hspace{+3mm}1.2 $max \leftarrow a.used$ \\ -\hspace{+3mm}1.3 $x \leftarrow a$ \\ -2. else \\ -\hspace{+3mm}2.1 $min \leftarrow a.used$ \\ -\hspace{+3mm}2.2 $max \leftarrow b.used$ \\ -\hspace{+3mm}2.3 $x \leftarrow b$ \\ -3. If $c.alloc < max + 1$ then grow $c$ to hold at least $max + 1$ digits (\textit{mp\_grow}) \\ -4. If failed to grow $c$ return(\textit{MP\_MEM}) \\ -5. $oldused \leftarrow c.used$ \\ -6. $c.used \leftarrow max + 1$ \\ -7. $u \leftarrow 0$ \\ -8. for $n$ from $0$ to $min - 1$ do \\ -\hspace{+3mm}8.1 $c_n \leftarrow a_n + b_n + u$ \\ -\hspace{+3mm}8.2 $u \leftarrow c_n >> lg(\beta)$ \\ -\hspace{+3mm}8.3 $c_n \leftarrow c_n \mbox{ (mod }\beta\mbox{)}$ \\ -9. if $min \ne max$ then do \\ -\hspace{+3mm}9.1 for $n$ from $min$ to $max - 1$ do \\ -\hspace{+6mm}9.1.1 $c_n \leftarrow x_n + u$ \\ -\hspace{+6mm}9.1.2 $u \leftarrow c_n >> lg(\beta)$ \\ -\hspace{+6mm}9.1.3 $c_n \leftarrow c_n \mbox{ (mod }\beta\mbox{)}$ \\ -10. $c_{max} \leftarrow u$ \\ -11. if $olduse > max$ then \\ -\hspace{+3mm}11.1 for $n$ from $max + 1$ to $olduse - 1$ do \\ -\hspace{+6mm}11.1.1 $c_n \leftarrow 0$ \\ -12. Clamp excess digits in $c$. (\textit{mp\_clamp}) \\ -13. Return(\textit{MP\_OKAY}) \\ -\hline -\end{tabular} -\end{small} -\end{center} -\caption{Algorithm s\_mp\_add} -\end{figure} - -\textbf{Algorithm s\_mp\_add.} -This algorithm is loosely based on algorithm 14.7 of HAC \cite[pp. 594]{HAC} but has been extended to allow the inputs to have different magnitudes. -Coincidentally the description of algorithm A in Knuth \cite[pp. 266]{TAOCPV2} shares the same deficiency as the algorithm from \cite{HAC}. Even the -MIX pseudo machine code presented by Knuth \cite[pp. 266-267]{TAOCPV2} is incapable of handling inputs which are of different magnitudes. - -Steps 1 and 2 will sort the two inputs based on their \textbf{used} digit count. This allows the inputs to have varying magnitudes which not -only makes it more efficient than the trivial algorithm presented in the references but more flexible. The variable $min$ is given the lowest -digit count while $max$ is given the highest digit count. If both inputs have the same \textbf{used} digit count both $min$ and $max$ are -set to the same value. The variable $x$ is an \textit{alias} for the largest input and not meant to be a copy of it. After the inputs are sorted, -steps 3 and 4 will ensure that the destination $c$ can accommodate the result. The old \textbf{used} count from $c$ is copied to -$oldused$ so that excess digits can be cleared later, and the new \textbf{used} count is set to $max+1$, so that a carry from the most significant -word can be handled. - -At step 7 the carry variable $u$ is set to zero and the first part of the addition loop can begin. The first step of the loop (\textit{8.1}) adds -digits from the two inputs together along with the carry variable $u$. The following step extracts the carry bit by shifting the result of the -preceding step right by $lg(\beta)$ positions. The shift to extract the carry is similar to how carry extraction works with decimal addition. - -Consider adding $77$ to $65$, the first addition of the first column is $7 + 5$ which produces the result $12$. The trailing digit of the result -is $2 \equiv 12 \mbox{ (mod }10\mbox{)}$ and the carry is found by dividing (\textit{and ignoring the remainder}) $12$ by the radix or in this case $10$. The -division and multiplication of $10$ is simply a logical right or left shift, respectively, of the digits. In otherwords the carry can be extracted -by shifting one digit to the right. - -Note that $lg()$ is simply the base two logarithm such that $lg(2^k) = k$. This implies that $lg(\beta)$ is the number of bits in a radix-$\beta$ -digit. Therefore, a logical shift right of the summand by $lg(\beta)$ will extract the carry. The final step of the loop reduces the digit -modulo the radix $\beta$ to ensure it is in range. - -After step 8 the smallest input (\textit{or both if they are the same magnitude}) has been exhausted. Step 9 decides whether -the inputs were of equal magnitude. If not than another loop similar to that in step 8, must be executed. The loop at step -number 9.1 differs from the previous loop since it only adds the mp\_int $x$ along with the carry. - -Step 10 finishes the addition phase by copying the final carry to the highest location in the result $c_{max}$. Step 11 ensures that -leading digits that were originally present in $c$ are cleared. Finally excess leading digits are clamped and the algorithm returns success. - -EXAM,bn_s_mp_add.c - -Lines @27,if@ to @35,}@ perform the initial sorting of the inputs and determine the $min$ and $max$ variables. Note that $x$ is a pointer to a -mp\_int assigned to the largest input, in effect it is a local alias. Lines @37,init@ to @42,}@ ensure that the destination is grown to -accomodate the result of the addition. - -Similar to the implementation of mp\_copy this function uses the braced code and local aliases coding style. The three aliases that are on -lines @56,tmpa@, @59,tmpb@ and @62,tmpc@ represent the two inputs and destination variables respectively. These aliases are used to ensure the -compiler does not have to dereference $a$, $b$ or $c$ (respectively) to access the digits of the respective mp\_int. - -The initial carry $u$ is cleared on line @65,u = 0@, note that $u$ is of type mp\_digit which ensures type compatibility within the -implementation. The initial addition loop begins on line @66,for@ and ends on line @75,}@. Similarly the conditional addition loop -begins on line @81,for@ and ends on line @90,}@. The addition is finished with the final carry being stored in $tmpc$ on line @94,tmpc++@. -Note the ``++'' operator on the same line. After line @94,tmpc++@ $tmpc$ will point to the $c.used$'th digit of the mp\_int $c$. This is useful -for the next loop on lines @97,for@ to @99,}@ which set any old upper digits to zero. - -\subsection{Low Level Subtraction} -The low level unsigned subtraction algorithm is very similar to the low level unsigned addition algorithm. The principle difference is that the -unsigned subtraction algorithm requires the result to be positive. That is when computing $a - b$ the condition $\vert a \vert \ge \vert b\vert$ must -be met for this algorithm to function properly. Keep in mind this low level algorithm is not meant to be used in higher level algorithms directly. -This algorithm as will be shown can be used to create functional signed addition and subtraction algorithms. - -MARK,GAMMA - -For this algorithm a new variable is required to make the description simpler. Recall from section 1.3.1 that a mp\_digit must be able to represent -the range $0 \le x < 2\beta$ for the algorithms to work correctly. However, it is allowable that a mp\_digit represent a larger range of values. For -this algorithm we will assume that the variable $\gamma$ represents the number of bits available in a -mp\_digit (\textit{this implies $2^{\gamma} > \beta$}). - -For example, the default for LibTomMath is to use a ``unsigned long'' for the mp\_digit ``type'' while $\beta = 2^{28}$. In ISO C an ``unsigned long'' -data type must be able to represent $0 \le x < 2^{32}$ meaning that in this case $\gamma = 32$. - -\newpage\begin{figure}[!here] -\begin{center} -\begin{small} -\begin{tabular}{l} -\hline Algorithm \textbf{s\_mp\_sub}. \\ -\textbf{Input}. Two mp\_ints $a$ and $b$ ($\vert a \vert \ge \vert b \vert$) \\ -\textbf{Output}. The unsigned subtraction $c = \vert a \vert - \vert b \vert$. \\ -\hline \\ -1. $min \leftarrow b.used$ \\ -2. $max \leftarrow a.used$ \\ -3. If $c.alloc < max$ then grow $c$ to hold at least $max$ digits. (\textit{mp\_grow}) \\ -4. If the reallocation failed return(\textit{MP\_MEM}). \\ -5. $oldused \leftarrow c.used$ \\ -6. $c.used \leftarrow max$ \\ -7. $u \leftarrow 0$ \\ -8. for $n$ from $0$ to $min - 1$ do \\ -\hspace{3mm}8.1 $c_n \leftarrow a_n - b_n - u$ \\ -\hspace{3mm}8.2 $u \leftarrow c_n >> (\gamma - 1)$ \\ -\hspace{3mm}8.3 $c_n \leftarrow c_n \mbox{ (mod }\beta\mbox{)}$ \\ -9. if $min < max$ then do \\ -\hspace{3mm}9.1 for $n$ from $min$ to $max - 1$ do \\ -\hspace{6mm}9.1.1 $c_n \leftarrow a_n - u$ \\ -\hspace{6mm}9.1.2 $u \leftarrow c_n >> (\gamma - 1)$ \\ -\hspace{6mm}9.1.3 $c_n \leftarrow c_n \mbox{ (mod }\beta\mbox{)}$ \\ -10. if $oldused > max$ then do \\ -\hspace{3mm}10.1 for $n$ from $max$ to $oldused - 1$ do \\ -\hspace{6mm}10.1.1 $c_n \leftarrow 0$ \\ -11. Clamp excess digits of $c$. (\textit{mp\_clamp}). \\ -12. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{small} -\end{center} -\caption{Algorithm s\_mp\_sub} -\end{figure} - -\textbf{Algorithm s\_mp\_sub.} -This algorithm performs the unsigned subtraction of two mp\_int variables under the restriction that the result must be positive. That is when -passing variables $a$ and $b$ the condition that $\vert a \vert \ge \vert b \vert$ must be met for the algorithm to function correctly. This -algorithm is loosely based on algorithm 14.9 \cite[pp. 595]{HAC} and is similar to algorithm S in \cite[pp. 267]{TAOCPV2} as well. As was the case -of the algorithm s\_mp\_add both other references lack discussion concerning various practical details such as when the inputs differ in magnitude. - -The initial sorting of the inputs is trivial in this algorithm since $a$ is guaranteed to have at least the same magnitude of $b$. Steps 1 and 2 -set the $min$ and $max$ variables. Unlike the addition routine there is guaranteed to be no carry which means that the final result can be at -most $max$ digits in length as opposed to $max + 1$. Similar to the addition algorithm the \textbf{used} count of $c$ is copied locally and -set to the maximal count for the operation. - -The subtraction loop that begins on step 8 is essentially the same as the addition loop of algorithm s\_mp\_add except single precision -subtraction is used instead. Note the use of the $\gamma$ variable to extract the carry (\textit{also known as the borrow}) within the subtraction -loops. Under the assumption that two's complement single precision arithmetic is used this will successfully extract the desired carry. - -For example, consider subtracting $0101_2$ from $0100_2$ where $\gamma = 4$ and $\beta = 2$. The least significant bit will force a carry upwards to -the third bit which will be set to zero after the borrow. After the very first bit has been subtracted $4 - 1 \equiv 0011_2$ will remain, When the -third bit of $0101_2$ is subtracted from the result it will cause another carry. In this case though the carry will be forced to propagate all the -way to the most significant bit. - -Recall that $\beta < 2^{\gamma}$. This means that if a carry does occur just before the $lg(\beta)$'th bit it will propagate all the way to the most -significant bit. Thus, the high order bits of the mp\_digit that are not part of the actual digit will either be all zero, or all one. All that -is needed is a single zero or one bit for the carry. Therefore a single logical shift right by $\gamma - 1$ positions is sufficient to extract the -carry. This method of carry extraction may seem awkward but the reason for it becomes apparent when the implementation is discussed. - -If $b$ has a smaller magnitude than $a$ then step 9 will force the carry and copy operation to propagate through the larger input $a$ into $c$. Step -10 will ensure that any leading digits of $c$ above the $max$'th position are zeroed. - -EXAM,bn_s_mp_sub.c - -Line @24,min@ and @25,max@ perform the initial hardcoded sorting of the inputs. In reality the $min$ and $max$ variables are only aliases and are only -used to make the source code easier to read. Again the pointer alias optimization is used within this algorithm. Lines @42,tmpa@, @43,tmpb@ and @44,tmpc@ initialize the aliases for -$a$, $b$ and $c$ respectively. - -The first subtraction loop occurs on lines @47,u = 0@ through @61,}@. The theory behind the subtraction loop is exactly the same as that for -the addition loop. As remarked earlier there is an implementation reason for using the ``awkward'' method of extracting the carry -(\textit{see line @57, >>@}). The traditional method for extracting the carry would be to shift by $lg(\beta)$ positions and logically AND -the least significant bit. The AND operation is required because all of the bits above the $\lg(\beta)$'th bit will be set to one after a carry -occurs from subtraction. This carry extraction requires two relatively cheap operations to extract the carry. The other method is to simply -shift the most significant bit to the least significant bit thus extracting the carry with a single cheap operation. This optimization only works on -twos compliment machines which is a safe assumption to make. - -If $a$ has a larger magnitude than $b$ an additional loop (\textit{see lines @64,for@ through @73,}@}) is required to propagate the carry through -$a$ and copy the result to $c$. - -\subsection{High Level Addition} -Now that both lower level addition and subtraction algorithms have been established an effective high level signed addition algorithm can be -established. This high level addition algorithm will be what other algorithms and developers will use to perform addition of mp\_int data -types. - -Recall from section 5.2 that an mp\_int represents an integer with an unsigned mantissa (\textit{the array of digits}) and a \textbf{sign} -flag. A high level addition is actually performed as a series of eight separate cases which can be optimized down to three unique cases. - -\begin{figure}[!here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_add}. \\ -\textbf{Input}. Two mp\_ints $a$ and $b$ \\ -\textbf{Output}. The signed addition $c = a + b$. \\ -\hline \\ -1. if $a.sign = b.sign$ then do \\ -\hspace{3mm}1.1 $c.sign \leftarrow a.sign$ \\ -\hspace{3mm}1.2 $c \leftarrow \vert a \vert + \vert b \vert$ (\textit{s\_mp\_add})\\ -2. else do \\ -\hspace{3mm}2.1 if $\vert a \vert < \vert b \vert$ then do (\textit{mp\_cmp\_mag}) \\ -\hspace{6mm}2.1.1 $c.sign \leftarrow b.sign$ \\ -\hspace{6mm}2.1.2 $c \leftarrow \vert b \vert - \vert a \vert$ (\textit{s\_mp\_sub}) \\ -\hspace{3mm}2.2 else do \\ -\hspace{6mm}2.2.1 $c.sign \leftarrow a.sign$ \\ -\hspace{6mm}2.2.2 $c \leftarrow \vert a \vert - \vert b \vert$ \\ -3. If any of the lower level operations failed return(\textit{MP\_MEM}) \\ -4. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_add} -\end{figure} - -\textbf{Algorithm mp\_add.} -This algorithm performs the signed addition of two mp\_int variables. There is no reference algorithm to draw upon from either \cite{TAOCPV2} or -\cite{HAC} since they both only provide unsigned operations. The algorithm is fairly straightforward but restricted since subtraction can only -produce positive results. - -\begin{figure}[here] -\begin{small} -\begin{center} -\begin{tabular}{|c|c|c|c|c|} -\hline \textbf{Sign of $a$} & \textbf{Sign of $b$} & \textbf{$\vert a \vert > \vert b \vert $} & \textbf{Unsigned Operation} & \textbf{Result Sign Flag} \\ -\hline $+$ & $+$ & Yes & $c = a + b$ & $a.sign$ \\ -\hline $+$ & $+$ & No & $c = a + b$ & $a.sign$ \\ -\hline $-$ & $-$ & Yes & $c = a + b$ & $a.sign$ \\ -\hline $-$ & $-$ & No & $c = a + b$ & $a.sign$ \\ -\hline &&&&\\ - -\hline $+$ & $-$ & No & $c = b - a$ & $b.sign$ \\ -\hline $-$ & $+$ & No & $c = b - a$ & $b.sign$ \\ - -\hline &&&&\\ - -\hline $+$ & $-$ & Yes & $c = a - b$ & $a.sign$ \\ -\hline $-$ & $+$ & Yes & $c = a - b$ & $a.sign$ \\ - -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Addition Guide Chart} -\label{fig:AddChart} -\end{figure} - -Figure~\ref{fig:AddChart} lists all of the eight possible input combinations and is sorted to show that only three specific cases need to be handled. The -return code of the unsigned operations at step 1.2, 2.1.2 and 2.2.2 are forwarded to step 3 to check for errors. This simplifies the description -of the algorithm considerably and best follows how the implementation actually was achieved. - -Also note how the \textbf{sign} is set before the unsigned addition or subtraction is performed. Recall from the descriptions of algorithms -s\_mp\_add and s\_mp\_sub that the mp\_clamp function is used at the end to trim excess digits. The mp\_clamp algorithm will set the \textbf{sign} -to \textbf{MP\_ZPOS} when the \textbf{used} digit count reaches zero. - -For example, consider performing $-a + a$ with algorithm mp\_add. By the description of the algorithm the sign is set to \textbf{MP\_NEG} which would -produce a result of $-0$. However, since the sign is set first then the unsigned addition is performed the subsequent usage of algorithm mp\_clamp -within algorithm s\_mp\_add will force $-0$ to become $0$. - -EXAM,bn_mp_add.c - -The source code follows the algorithm fairly closely. The most notable new source code addition is the usage of the $res$ integer variable which -is used to pass result of the unsigned operations forward. Unlike in the algorithm, the variable $res$ is merely returned as is without -explicitly checking it and returning the constant \textbf{MP\_OKAY}. The observation is this algorithm will succeed or fail only if the lower -level functions do so. Returning their return code is sufficient. - -\subsection{High Level Subtraction} -The high level signed subtraction algorithm is essentially the same as the high level signed addition algorithm. - -\newpage\begin{figure}[!here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_sub}. \\ -\textbf{Input}. Two mp\_ints $a$ and $b$ \\ -\textbf{Output}. The signed subtraction $c = a - b$. \\ -\hline \\ -1. if $a.sign \ne b.sign$ then do \\ -\hspace{3mm}1.1 $c.sign \leftarrow a.sign$ \\ -\hspace{3mm}1.2 $c \leftarrow \vert a \vert + \vert b \vert$ (\textit{s\_mp\_add}) \\ -2. else do \\ -\hspace{3mm}2.1 if $\vert a \vert \ge \vert b \vert$ then do (\textit{mp\_cmp\_mag}) \\ -\hspace{6mm}2.1.1 $c.sign \leftarrow a.sign$ \\ -\hspace{6mm}2.1.2 $c \leftarrow \vert a \vert - \vert b \vert$ (\textit{s\_mp\_sub}) \\ -\hspace{3mm}2.2 else do \\ -\hspace{6mm}2.2.1 $c.sign \leftarrow \left \lbrace \begin{array}{ll} - MP\_ZPOS & \mbox{if }a.sign = MP\_NEG \\ - MP\_NEG & \mbox{otherwise} \\ - \end{array} \right .$ \\ -\hspace{6mm}2.2.2 $c \leftarrow \vert b \vert - \vert a \vert$ \\ -3. If any of the lower level operations failed return(\textit{MP\_MEM}). \\ -4. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_sub} -\end{figure} - -\textbf{Algorithm mp\_sub.} -This algorithm performs the signed subtraction of two inputs. Similar to algorithm mp\_add there is no reference in either \cite{TAOCPV2} or -\cite{HAC}. Also this algorithm is restricted by algorithm s\_mp\_sub. The following chart lists the eight possible inputs and -the operations required. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{|c|c|c|c|c|} -\hline \textbf{Sign of $a$} & \textbf{Sign of $b$} & \textbf{$\vert a \vert \ge \vert b \vert $} & \textbf{Unsigned Operation} & \textbf{Result Sign Flag} \\ -\hline $+$ & $-$ & Yes & $c = a + b$ & $a.sign$ \\ -\hline $+$ & $-$ & No & $c = a + b$ & $a.sign$ \\ -\hline $-$ & $+$ & Yes & $c = a + b$ & $a.sign$ \\ -\hline $-$ & $+$ & No & $c = a + b$ & $a.sign$ \\ -\hline &&&& \\ -\hline $+$ & $+$ & Yes & $c = a - b$ & $a.sign$ \\ -\hline $-$ & $-$ & Yes & $c = a - b$ & $a.sign$ \\ -\hline &&&& \\ -\hline $+$ & $+$ & No & $c = b - a$ & $\mbox{opposite of }a.sign$ \\ -\hline $-$ & $-$ & No & $c = b - a$ & $\mbox{opposite of }a.sign$ \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Subtraction Guide Chart} -\end{figure} - -Similar to the case of algorithm mp\_add the \textbf{sign} is set first before the unsigned addition or subtraction. That is to prevent the -algorithm from producing $-a - -a = -0$ as a result. - -EXAM,bn_mp_sub.c - -Much like the implementation of algorithm mp\_add the variable $res$ is used to catch the return code of the unsigned addition or subtraction operations -and forward it to the end of the function. On line @38, != MP_LT@ the ``not equal to'' \textbf{MP\_LT} expression is used to emulate a -``greater than or equal to'' comparison. - -\section{Bit and Digit Shifting} -MARK,POLY -It is quite common to think of a multiple precision integer as a polynomial in $x$, that is $y = f(\beta)$ where $f(x) = \sum_{i=0}^{n-1} a_i x^i$. -This notation arises within discussion of Montgomery and Diminished Radix Reduction as well as Karatsuba multiplication and squaring. - -In order to facilitate operations on polynomials in $x$ as above a series of simple ``digit'' algorithms have to be established. That is to shift -the digits left or right as well to shift individual bits of the digits left and right. It is important to note that not all ``shift'' operations -are on radix-$\beta$ digits. - -\subsection{Multiplication by Two} - -In a binary system where the radix is a power of two multiplication by two not only arises often in other algorithms it is a fairly efficient -operation to perform. A single precision logical shift left is sufficient to multiply a single digit by two. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_mul\_2}. \\ -\textbf{Input}. One mp\_int $a$ \\ -\textbf{Output}. $b = 2a$. \\ -\hline \\ -1. If $b.alloc < a.used + 1$ then grow $b$ to hold $a.used + 1$ digits. (\textit{mp\_grow}) \\ -2. If the reallocation failed return(\textit{MP\_MEM}). \\ -3. $oldused \leftarrow b.used$ \\ -4. $b.used \leftarrow a.used$ \\ -5. $r \leftarrow 0$ \\ -6. for $n$ from 0 to $a.used - 1$ do \\ -\hspace{3mm}6.1 $rr \leftarrow a_n >> (lg(\beta) - 1)$ \\ -\hspace{3mm}6.2 $b_n \leftarrow (a_n << 1) + r \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{3mm}6.3 $r \leftarrow rr$ \\ -7. If $r \ne 0$ then do \\ -\hspace{3mm}7.1 $b_{n + 1} \leftarrow r$ \\ -\hspace{3mm}7.2 $b.used \leftarrow b.used + 1$ \\ -8. If $b.used < oldused - 1$ then do \\ -\hspace{3mm}8.1 for $n$ from $b.used$ to $oldused - 1$ do \\ -\hspace{6mm}8.1.1 $b_n \leftarrow 0$ \\ -9. $b.sign \leftarrow a.sign$ \\ -10. Return(\textit{MP\_OKAY}).\\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_mul\_2} -\end{figure} - -\textbf{Algorithm mp\_mul\_2.} -This algorithm will quickly multiply a mp\_int by two provided $\beta$ is a power of two. Neither \cite{TAOCPV2} nor \cite{HAC} describe such -an algorithm despite the fact it arises often in other algorithms. The algorithm is setup much like the lower level algorithm s\_mp\_add since -it is for all intents and purposes equivalent to the operation $b = \vert a \vert + \vert a \vert$. - -Step 1 and 2 grow the input as required to accomodate the maximum number of \textbf{used} digits in the result. The initial \textbf{used} count -is set to $a.used$ at step 4. Only if there is a final carry will the \textbf{used} count require adjustment. - -Step 6 is an optimization implementation of the addition loop for this specific case. That is since the two values being added together -are the same there is no need to perform two reads from the digits of $a$. Step 6.1 performs a single precision shift on the current digit $a_n$ to -obtain what will be the carry for the next iteration. Step 6.2 calculates the $n$'th digit of the result as single precision shift of $a_n$ plus -the previous carry. Recall from ~SHIFTS~ that $a_n << 1$ is equivalent to $a_n \cdot 2$. An iteration of the addition loop is finished with -forwarding the carry to the next iteration. - -Step 7 takes care of any final carry by setting the $a.used$'th digit of the result to the carry and augmenting the \textbf{used} count of $b$. -Step 8 clears any leading digits of $b$ in case it originally had a larger magnitude than $a$. - -EXAM,bn_mp_mul_2.c - -This implementation is essentially an optimized implementation of s\_mp\_add for the case of doubling an input. The only noteworthy difference -is the use of the logical shift operator on line @52,<<@ to perform a single precision doubling. - -\subsection{Division by Two} -A division by two can just as easily be accomplished with a logical shift right as multiplication by two can be with a logical shift left. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_div\_2}. \\ -\textbf{Input}. One mp\_int $a$ \\ -\textbf{Output}. $b = a/2$. \\ -\hline \\ -1. If $b.alloc < a.used$ then grow $b$ to hold $a.used$ digits. (\textit{mp\_grow}) \\ -2. If the reallocation failed return(\textit{MP\_MEM}). \\ -3. $oldused \leftarrow b.used$ \\ -4. $b.used \leftarrow a.used$ \\ -5. $r \leftarrow 0$ \\ -6. for $n$ from $b.used - 1$ to $0$ do \\ -\hspace{3mm}6.1 $rr \leftarrow a_n \mbox{ (mod }2\mbox{)}$\\ -\hspace{3mm}6.2 $b_n \leftarrow (a_n >> 1) + (r << (lg(\beta) - 1)) \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{3mm}6.3 $r \leftarrow rr$ \\ -7. If $b.used < oldused - 1$ then do \\ -\hspace{3mm}7.1 for $n$ from $b.used$ to $oldused - 1$ do \\ -\hspace{6mm}7.1.1 $b_n \leftarrow 0$ \\ -8. $b.sign \leftarrow a.sign$ \\ -9. Clamp excess digits of $b$. (\textit{mp\_clamp}) \\ -10. Return(\textit{MP\_OKAY}).\\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_div\_2} -\end{figure} - -\textbf{Algorithm mp\_div\_2.} -This algorithm will divide an mp\_int by two using logical shifts to the right. Like mp\_mul\_2 it uses a modified low level addition -core as the basis of the algorithm. Unlike mp\_mul\_2 the shift operations work from the leading digit to the trailing digit. The algorithm -could be written to work from the trailing digit to the leading digit however, it would have to stop one short of $a.used - 1$ digits to prevent -reading past the end of the array of digits. - -Essentially the loop at step 6 is similar to that of mp\_mul\_2 except the logical shifts go in the opposite direction and the carry is at the -least significant bit not the most significant bit. - -EXAM,bn_mp_div_2.c - -\section{Polynomial Basis Operations} -Recall from ~POLY~ that any integer can be represented as a polynomial in $x$ as $y = f(\beta)$. Such a representation is also known as -the polynomial basis \cite[pp. 48]{ROSE}. Given such a notation a multiplication or division by $x$ amounts to shifting whole digits a single -place. The need for such operations arises in several other higher level algorithms such as Barrett and Montgomery reduction, integer -division and Karatsuba multiplication. - -Converting from an array of digits to polynomial basis is very simple. Consider the integer $y \equiv (a_2, a_1, a_0)_{\beta}$ and recall that -$y = \sum_{i=0}^{2} a_i \beta^i$. Simply replace $\beta$ with $x$ and the expression is in polynomial basis. For example, $f(x) = 8x + 9$ is the -polynomial basis representation for $89$ using radix ten. That is, $f(10) = 8(10) + 9 = 89$. - -\subsection{Multiplication by $x$} - -Given a polynomial in $x$ such as $f(x) = a_n x^n + a_{n-1} x^{n-1} + ... + a_0$ multiplying by $x$ amounts to shifting the coefficients up one -degree. In this case $f(x) \cdot x = a_n x^{n+1} + a_{n-1} x^n + ... + a_0 x$. From a scalar basis point of view multiplying by $x$ is equivalent to -multiplying by the integer $\beta$. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_lshd}. \\ -\textbf{Input}. One mp\_int $a$ and an integer $b$ \\ -\textbf{Output}. $a \leftarrow a \cdot \beta^b$ (equivalent to multiplication by $x^b$). \\ -\hline \\ -1. If $b \le 0$ then return(\textit{MP\_OKAY}). \\ -2. If $a.alloc < a.used + b$ then grow $a$ to at least $a.used + b$ digits. (\textit{mp\_grow}). \\ -3. If the reallocation failed return(\textit{MP\_MEM}). \\ -4. $a.used \leftarrow a.used + b$ \\ -5. $i \leftarrow a.used - 1$ \\ -6. $j \leftarrow a.used - 1 - b$ \\ -7. for $n$ from $a.used - 1$ to $b$ do \\ -\hspace{3mm}7.1 $a_{i} \leftarrow a_{j}$ \\ -\hspace{3mm}7.2 $i \leftarrow i - 1$ \\ -\hspace{3mm}7.3 $j \leftarrow j - 1$ \\ -8. for $n$ from 0 to $b - 1$ do \\ -\hspace{3mm}8.1 $a_n \leftarrow 0$ \\ -9. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_lshd} -\end{figure} - -\textbf{Algorithm mp\_lshd.} -This algorithm multiplies an mp\_int by the $b$'th power of $x$. This is equivalent to multiplying by $\beta^b$. The algorithm differs -from the other algorithms presented so far as it performs the operation in place instead storing the result in a separate location. The -motivation behind this change is due to the way this function is typically used. Algorithms such as mp\_add store the result in an optionally -different third mp\_int because the original inputs are often still required. Algorithm mp\_lshd (\textit{and similarly algorithm mp\_rshd}) is -typically used on values where the original value is no longer required. The algorithm will return success immediately if -$b \le 0$ since the rest of algorithm is only valid when $b > 0$. - -First the destination $a$ is grown as required to accomodate the result. The counters $i$ and $j$ are used to form a \textit{sliding window} over -the digits of $a$ of length $b$. The head of the sliding window is at $i$ (\textit{the leading digit}) and the tail at $j$ (\textit{the trailing digit}). -The loop on step 7 copies the digit from the tail to the head. In each iteration the window is moved down one digit. The last loop on -step 8 sets the lower $b$ digits to zero. - -\newpage -FIGU,sliding_window,Sliding Window Movement - -EXAM,bn_mp_lshd.c - -The if statement on line @24,if@ ensures that the $b$ variable is greater than zero. The \textbf{used} count is incremented by $b$ before -the copy loop begins. This elminates the need for an additional variable in the for loop. The variable $top$ on line @42,top@ is an alias -for the leading digit while $bottom$ on line @45,bottom@ is an alias for the trailing edge. The aliases form a window of exactly $b$ digits -over the input. - -\subsection{Division by $x$} - -Division by powers of $x$ is easily achieved by shifting the digits right and removing any that will end up to the right of the zero'th digit. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_rshd}. \\ -\textbf{Input}. One mp\_int $a$ and an integer $b$ \\ -\textbf{Output}. $a \leftarrow a / \beta^b$ (Divide by $x^b$). \\ -\hline \\ -1. If $b \le 0$ then return. \\ -2. If $a.used \le b$ then do \\ -\hspace{3mm}2.1 Zero $a$. (\textit{mp\_zero}). \\ -\hspace{3mm}2.2 Return. \\ -3. $i \leftarrow 0$ \\ -4. $j \leftarrow b$ \\ -5. for $n$ from 0 to $a.used - b - 1$ do \\ -\hspace{3mm}5.1 $a_i \leftarrow a_j$ \\ -\hspace{3mm}5.2 $i \leftarrow i + 1$ \\ -\hspace{3mm}5.3 $j \leftarrow j + 1$ \\ -6. for $n$ from $a.used - b$ to $a.used - 1$ do \\ -\hspace{3mm}6.1 $a_n \leftarrow 0$ \\ -7. $a.used \leftarrow a.used - b$ \\ -8. Return. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_rshd} -\end{figure} - -\textbf{Algorithm mp\_rshd.} -This algorithm divides the input in place by the $b$'th power of $x$. It is analogous to dividing by a $\beta^b$ but much quicker since -it does not require single precision division. This algorithm does not actually return an error code as it cannot fail. - -If the input $b$ is less than one the algorithm quickly returns without performing any work. If the \textbf{used} count is less than or equal -to the shift count $b$ then it will simply zero the input and return. - -After the trivial cases of inputs have been handled the sliding window is setup. Much like the case of algorithm mp\_lshd a sliding window that -is $b$ digits wide is used to copy the digits. Unlike mp\_lshd the window slides in the opposite direction from the trailing to the leading digit. -Also the digits are copied from the leading to the trailing edge. - -Once the window copy is complete the upper digits must be zeroed and the \textbf{used} count decremented. - -EXAM,bn_mp_rshd.c - -The only noteworthy element of this routine is the lack of a return type. - --- Will update later to give it a return type...Tom - -\section{Powers of Two} - -Now that algorithms for moving single bits as well as whole digits exist algorithms for moving the ``in between'' distances are required. For -example, to quickly multiply by $2^k$ for any $k$ without using a full multiplier algorithm would prove useful. Instead of performing single -shifts $k$ times to achieve a multiplication by $2^{\pm k}$ a mixture of whole digit shifting and partial digit shifting is employed. - -\subsection{Multiplication by Power of Two} - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_mul\_2d}. \\ -\textbf{Input}. One mp\_int $a$ and an integer $b$ \\ -\textbf{Output}. $c \leftarrow a \cdot 2^b$. \\ -\hline \\ -1. $c \leftarrow a$. (\textit{mp\_copy}) \\ -2. If $c.alloc < c.used + \lfloor b / lg(\beta) \rfloor + 2$ then grow $c$ accordingly. \\ -3. If the reallocation failed return(\textit{MP\_MEM}). \\ -4. If $b \ge lg(\beta)$ then \\ -\hspace{3mm}4.1 $c \leftarrow c \cdot \beta^{\lfloor b / lg(\beta) \rfloor}$ (\textit{mp\_lshd}). \\ -\hspace{3mm}4.2 If step 4.1 failed return(\textit{MP\_MEM}). \\ -5. $d \leftarrow b \mbox{ (mod }lg(\beta)\mbox{)}$ \\ -6. If $d \ne 0$ then do \\ -\hspace{3mm}6.1 $mask \leftarrow 2^d$ \\ -\hspace{3mm}6.2 $r \leftarrow 0$ \\ -\hspace{3mm}6.3 for $n$ from $0$ to $c.used - 1$ do \\ -\hspace{6mm}6.3.1 $rr \leftarrow c_n >> (lg(\beta) - d) \mbox{ (mod }mask\mbox{)}$ \\ -\hspace{6mm}6.3.2 $c_n \leftarrow (c_n << d) + r \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{6mm}6.3.3 $r \leftarrow rr$ \\ -\hspace{3mm}6.4 If $r > 0$ then do \\ -\hspace{6mm}6.4.1 $c_{c.used} \leftarrow r$ \\ -\hspace{6mm}6.4.2 $c.used \leftarrow c.used + 1$ \\ -7. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_mul\_2d} -\end{figure} - -\textbf{Algorithm mp\_mul\_2d.} -This algorithm multiplies $a$ by $2^b$ and stores the result in $c$. The algorithm uses algorithm mp\_lshd and a derivative of algorithm mp\_mul\_2 to -quickly compute the product. - -First the algorithm will multiply $a$ by $x^{\lfloor b / lg(\beta) \rfloor}$ which will ensure that the remainder multiplicand is less than -$\beta$. For example, if $b = 37$ and $\beta = 2^{28}$ then this step will multiply by $x$ leaving a multiplication by $2^{37 - 28} = 2^{9}$ -left. - -After the digits have been shifted appropriately at most $lg(\beta) - 1$ shifts are left to perform. Step 5 calculates the number of remaining shifts -required. If it is non-zero a modified shift loop is used to calculate the remaining product. -Essentially the loop is a generic version of algorith mp\_mul2 designed to handle any shift count in the range $1 \le x < lg(\beta)$. The $mask$ -variable is used to extract the upper $d$ bits to form the carry for the next iteration. - -This algorithm is loosely measured as a $O(2n)$ algorithm which means that if the input is $n$-digits that it takes $2n$ ``time'' to -complete. It is possible to optimize this algorithm down to a $O(n)$ algorithm at a cost of making the algorithm slightly harder to follow. - -EXAM,bn_mp_mul_2d.c - -Notes to be revised when code is updated. -- Tom - -\subsection{Division by Power of Two} - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_div\_2d}. \\ -\textbf{Input}. One mp\_int $a$ and an integer $b$ \\ -\textbf{Output}. $c \leftarrow \lfloor a / 2^b \rfloor, d \leftarrow a \mbox{ (mod }2^b\mbox{)}$. \\ -\hline \\ -1. If $b \le 0$ then do \\ -\hspace{3mm}1.1 $c \leftarrow a$ (\textit{mp\_copy}) \\ -\hspace{3mm}1.2 $d \leftarrow 0$ (\textit{mp\_zero}) \\ -\hspace{3mm}1.3 Return(\textit{MP\_OKAY}). \\ -2. $c \leftarrow a$ \\ -3. $d \leftarrow a \mbox{ (mod }2^b\mbox{)}$ (\textit{mp\_mod\_2d}) \\ -4. If $b \ge lg(\beta)$ then do \\ -\hspace{3mm}4.1 $c \leftarrow \lfloor c/\beta^{\lfloor b/lg(\beta) \rfloor} \rfloor$ (\textit{mp\_rshd}). \\ -5. $k \leftarrow b \mbox{ (mod }lg(\beta)\mbox{)}$ \\ -6. If $k \ne 0$ then do \\ -\hspace{3mm}6.1 $mask \leftarrow 2^k$ \\ -\hspace{3mm}6.2 $r \leftarrow 0$ \\ -\hspace{3mm}6.3 for $n$ from $c.used - 1$ to $0$ do \\ -\hspace{6mm}6.3.1 $rr \leftarrow c_n \mbox{ (mod }mask\mbox{)}$ \\ -\hspace{6mm}6.3.2 $c_n \leftarrow (c_n >> k) + (r << (lg(\beta) - k))$ \\ -\hspace{6mm}6.3.3 $r \leftarrow rr$ \\ -7. Clamp excess digits of $c$. (\textit{mp\_clamp}) \\ -8. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_div\_2d} -\end{figure} - -\textbf{Algorithm mp\_div\_2d.} -This algorithm will divide an input $a$ by $2^b$ and produce the quotient and remainder. The algorithm is designed much like algorithm -mp\_mul\_2d by first using whole digit shifts then single precision shifts. This algorithm will also produce the remainder of the division -by using algorithm mp\_mod\_2d. - -EXAM,bn_mp_div_2d.c - -The implementation of algorithm mp\_div\_2d is slightly different than the algorithm specifies. The remainder $d$ may be optionally -ignored by passing \textbf{NULL} as the pointer to the mp\_int variable. The temporary mp\_int variable $t$ is used to hold the -result of the remainder operation until the end. This allows $d$ and $a$ to represent the same mp\_int without modifying $a$ before -the quotient is obtained. - -The remainder of the source code is essentially the same as the source code for mp\_mul\_2d. (-- Fix this paragraph up later, Tom). - -\subsection{Remainder of Division by Power of Two} - -The last algorithm in the series of polynomial basis power of two algorithms is calculating the remainder of division by $2^b$. This -algorithm benefits from the fact that in twos complement arithmetic $a \mbox{ (mod }2^b\mbox{)}$ is the same as $a$ AND $2^b - 1$. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_mod\_2d}. \\ -\textbf{Input}. One mp\_int $a$ and an integer $b$ \\ -\textbf{Output}. $c \leftarrow a \mbox{ (mod }2^b\mbox{)}$. \\ -\hline \\ -1. If $b \le 0$ then do \\ -\hspace{3mm}1.1 $c \leftarrow 0$ (\textit{mp\_zero}) \\ -\hspace{3mm}1.2 Return(\textit{MP\_OKAY}). \\ -2. If $b > a.used \cdot lg(\beta)$ then do \\ -\hspace{3mm}2.1 $c \leftarrow a$ (\textit{mp\_copy}) \\ -\hspace{3mm}2.2 Return the result of step 2.1. \\ -3. $c \leftarrow a$ \\ -4. If step 3 failed return(\textit{MP\_MEM}). \\ -5. for $n$ from $\lceil b / lg(\beta) \rceil$ to $c.used$ do \\ -\hspace{3mm}5.1 $c_n \leftarrow 0$ \\ -6. $k \leftarrow b \mbox{ (mod }lg(\beta)\mbox{)}$ \\ -7. $c_{\lfloor b / lg(\beta) \rfloor} \leftarrow c_{\lfloor b / lg(\beta) \rfloor} \mbox{ (mod }2^{k}\mbox{)}$. \\ -8. Clamp excess digits of $c$. (\textit{mp\_clamp}) \\ -9. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_mod\_2d} -\end{figure} - -\textbf{Algorithm mp\_mod\_2d.} -This algorithm will quickly calculate the value of $a \mbox{ (mod }2^b\mbox{)}$. First if $b$ is less than or equal to zero the -result is set to zero. If $b$ is greater than the number of bits in $a$ then it simply copies $a$ to $c$ and returns. Otherwise, $a$ -is copied to $b$, leading digits are removed and the remaining leading digit is trimed to the exact bit count. - -EXAM,bn_mp_mod_2d.c - --- Add comments later, Tom. - -\section*{Exercises} -\begin{tabular}{cl} -$\left [ 3 \right ] $ & Devise an algorithm that performs $a \cdot 2^b$ for generic values of $b$ \\ - & in $O(n)$ time. \\ - &\\ -$\left [ 3 \right ] $ & Devise an efficient algorithm to multiply by small low hamming \\ - & weight values such as $3$, $5$ and $9$. Extend it to handle all values \\ - & upto $64$ with a hamming weight less than three. \\ - &\\ -$\left [ 2 \right ] $ & Modify the preceding algorithm to handle values of the form \\ - & $2^k - 1$ as well. \\ - &\\ -$\left [ 3 \right ] $ & Using only algorithms mp\_mul\_2, mp\_div\_2 and mp\_add create an \\ - & algorithm to multiply two integers in roughly $O(2n^2)$ time for \\ - & any $n$-bit input. Note that the time of addition is ignored in the \\ - & calculation. \\ - & \\ -$\left [ 5 \right ] $ & Improve the previous algorithm to have a working time of at most \\ - & $O \left (2^{(k-1)}n + \left ({2n^2 \over k} \right ) \right )$ for an appropriate choice of $k$. Again ignore \\ - & the cost of addition. \\ - & \\ -$\left [ 2 \right ] $ & Devise a chart to find optimal values of $k$ for the previous problem \\ - & for $n = 64 \ldots 1024$ in steps of $64$. \\ - & \\ -$\left [ 2 \right ] $ & Using only algorithms mp\_abs and mp\_sub devise another method for \\ - & calculating the result of a signed comparison. \\ - & -\end{tabular} - -\chapter{Multiplication and Squaring} -\section{The Multipliers} -For most number theoretic problems including certain public key cryptographic algorithms, the ``multipliers'' form the most important subset of -algorithms of any multiple precision integer package. The set of multiplier algorithms include integer multiplication, squaring and modular reduction -where in each of the algorithms single precision multiplication is the dominant operation performed. This chapter will discuss integer multiplication -and squaring, leaving modular reductions for the subsequent chapter. - -The importance of the multiplier algorithms is for the most part driven by the fact that certain popular public key algorithms are based on modular -exponentiation, that is computing $d \equiv a^b \mbox{ (mod }c\mbox{)}$ for some arbitrary choice of $a$, $b$, $c$ and $d$. During a modular -exponentiation the majority\footnote{Roughly speaking a modular exponentiation will spend about 40\% of the time performing modular reductions, -35\% of the time performing squaring and 25\% of the time performing multiplications.} of the processor time is spent performing single precision -multiplications. - -For centuries general purpose multiplication has required a lengthly $O(n^2)$ process, whereby each digit of one multiplicand has to be multiplied -against every digit of the other multiplicand. Traditional long-hand multiplication is based on this process; while the techniques can differ the -overall algorithm used is essentially the same. Only ``recently'' have faster algorithms been studied. First Karatsuba multiplication was discovered in -1962. This algorithm can multiply two numbers with considerably fewer single precision multiplications when compared to the long-hand approach. -This technique led to the discovery of polynomial basis algorithms (\textit{good reference?}) and subquently Fourier Transform based solutions. - -\section{Multiplication} -\subsection{The Baseline Multiplication} -\index{baseline multiplication} -Computing the product of two integers in software can be achieved using a trivial adaptation of the standard $O(n^2)$ long-hand multiplication -algorithm that school children are taught. The algorithm is considered an $O(n^2)$ algoritn since for two $n$-digit inputs $n^2$ single precision -multiplications are required. More specifically for a $m$ and $n$ digit input $m \cdot n$ single precision multiplications are required. To -simplify most discussions, it will be assumed that the inputs have comparable number of digits. - -The ``baseline multiplication'' algorithm is designed to act as the ``catch-all'' algorithm, only to be used when the faster algorithms cannot be -used. This algorithm does not use any particularly interesting optimizations and should ideally be avoided if possible. One important -facet of this algorithm, is that it has been modified to only produce a certain amount of output digits as resolution. The importance of this -modification will become evident during the discussion of Barrett modular reduction. Recall that for a $n$ and $m$ digit input the product -will be at most $n + m$ digits. Therefore, this algorithm can be reduced to a full multiplier by having it produce $n + m$ digits of the product. - -Recall from ~GAMMA~ the definition of $\gamma$ as the number of bits in the type \textbf{mp\_digit}. We shall now extend the variable set to -include $\alpha$ which shall represent the number of bits in the type \textbf{mp\_word}. This implies that $2^{\alpha} > 2 \cdot \beta^2$. The -constant $\delta = 2^{\alpha - 2lg(\beta)}$ will represent the maximal weight of any column in a product (\textit{see ~COMBA~ for more information}). - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{s\_mp\_mul\_digs}. \\ -\textbf{Input}. mp\_int $a$, mp\_int $b$ and an integer $digs$ \\ -\textbf{Output}. $c \leftarrow \vert a \vert \cdot \vert b \vert \mbox{ (mod }\beta^{digs}\mbox{)}$. \\ -\hline \\ -1. If min$(a.used, b.used) < \delta$ then do \\ -\hspace{3mm}1.1 Calculate $c = \vert a \vert \cdot \vert b \vert$ by the Comba method (\textit{see algorithm~\ref{fig:COMBAMULT}}). \\ -\hspace{3mm}1.2 Return the result of step 1.1 \\ -\\ -Allocate and initialize a temporary mp\_int. \\ -2. Init $t$ to be of size $digs$ \\ -3. If step 2 failed return(\textit{MP\_MEM}). \\ -4. $t.used \leftarrow digs$ \\ -\\ -Compute the product. \\ -5. for $ix$ from $0$ to $a.used - 1$ do \\ -\hspace{3mm}5.1 $u \leftarrow 0$ \\ -\hspace{3mm}5.2 $pb \leftarrow \mbox{min}(b.used, digs - ix)$ \\ -\hspace{3mm}5.3 If $pb < 1$ then goto step 6. \\ -\hspace{3mm}5.4 for $iy$ from $0$ to $pb - 1$ do \\ -\hspace{6mm}5.4.1 $\hat r \leftarrow t_{iy + ix} + a_{ix} \cdot b_{iy} + u$ \\ -\hspace{6mm}5.4.2 $t_{iy + ix} \leftarrow \hat r \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{6mm}5.4.3 $u \leftarrow \lfloor \hat r / \beta \rfloor$ \\ -\hspace{3mm}5.5 if $ix + pb < digs$ then do \\ -\hspace{6mm}5.5.1 $t_{ix + pb} \leftarrow u$ \\ -6. Clamp excess digits of $t$. \\ -7. Swap $c$ with $t$ \\ -8. Clear $t$ \\ -9. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm s\_mp\_mul\_digs} -\end{figure} - -\textbf{Algorithm s\_mp\_mul\_digs.} -This algorithm computes the unsigned product of two inputs $a$ and $b$, limited to an output precision of $digs$ digits. While it may seem -a bit awkward to modify the function from its simple $O(n^2)$ description, the usefulness of partial multipliers will arise in a subsequent -algorithm. The algorithm is loosely based on algorithm 14.12 from \cite[pp. 595]{HAC} and is similar to Algorithm M of Knuth \cite[pp. 268]{TAOCPV2}. -Algorithm s\_mp\_mul\_digs differs from these cited references since it can produce a variable output precision regardless of the precision of the -inputs. - -The first thing this algorithm checks for is whether a Comba multiplier can be used instead. If the minimum digit count of either -input is less than $\delta$, then the Comba method may be used instead. After the Comba method is ruled out, the baseline algorithm begins. A -temporary mp\_int variable $t$ is used to hold the intermediate result of the product. This allows the algorithm to be used to -compute products when either $a = c$ or $b = c$ without overwriting the inputs. - -All of step 5 is the infamous $O(n^2)$ multiplication loop slightly modified to only produce upto $digs$ digits of output. The $pb$ variable -is given the count of digits to read from $b$ inside the nested loop. If $pb \le 1$ then no more output digits can be produced and the algorithm -will exit the loop. The best way to think of the loops are as a series of $pb \times 1$ multiplications. That is, in each pass of the -innermost loop $a_{ix}$ is multiplied against $b$ and the result is added (\textit{with an appropriate shift}) to $t$. - -For example, consider multiplying $576$ by $241$. That is equivalent to computing $10^0(1)(576) + 10^1(4)(576) + 10^2(2)(576)$ which is best -visualized in the following table. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{|c|c|c|c|c|c|l|} -\hline && & 5 & 7 & 6 & \\ -\hline $\times$&& & 2 & 4 & 1 & \\ -\hline &&&&&&\\ - && & 5 & 7 & 6 & $10^0(1)(576)$ \\ - &2 & 3 & 6 & 1 & 6 & $10^1(4)(576) + 10^0(1)(576)$ \\ - 1 & 3 & 8 & 8 & 1 & 6 & $10^2(2)(576) + 10^1(4)(576) + 10^0(1)(576)$ \\ -\hline -\end{tabular} -\end{center} -\caption{Long-Hand Multiplication Diagram} -\end{figure} - -Each row of the product is added to the result after being shifted to the left (\textit{multiplied by a power of the radix}) by the appropriate -count. That is in pass $ix$ of the inner loop the product is added starting at the $ix$'th digit of the reult. - -Step 5.4.1 introduces the hat symbol (\textit{e.g. $\hat r$}) which represents a double precision variable. The multiplication on that step -is assumed to be a double wide output single precision multiplication. That is, two single precision variables are multiplied to produce a -double precision result. The step is somewhat optimized from a long-hand multiplication algorithm because the carry from the addition in step -5.4.1 is propagated through the nested loop. If the carry was not propagated immediately it would overflow the single precision digit -$t_{ix+iy}$ and the result would be lost. - -At step 5.5 the nested loop is finished and any carry that was left over should be forwarded. The carry does not have to be added to the $ix+pb$'th -digit since that digit is assumed to be zero at this point. However, if $ix + pb \ge digs$ the carry is not set as it would make the result -exceed the precision requested. - -EXAM,bn_s_mp_mul_digs.c - -Lines @31,if@ to @35,}@ determine if the Comba method can be used first. The conditions for using the Comba routine are that min$(a.used, b.used) < \delta$ and -the number of digits of output is less than \textbf{MP\_WARRAY}. This new constant is used to control -the stack usage in the Comba routines. By default it is set to $\delta$ but can be reduced when memory is at a premium. - -Of particular importance is the calculation of the $ix+iy$'th column on lines @64,mp_word@, @65,mp_word@ and @66,mp_word@. Note how all of the -variables are cast to the type \textbf{mp\_word}, which is also the type of variable $\hat r$. That is to ensure that double precision operations -are used instead of single precision. The multiplication on line @65,) * (@ makes use of a specific GCC optimizer behaviour. On the outset it looks like -the compiler will have to use a double precision multiplication to produce the result required. Such an operation would be horribly slow on most -processors and drag this to a crawl. However, GCC is smart enough to realize that double wide output single precision multipliers can be used. For -example, the instruction ``MUL'' on the x86 processor can multiply two 32-bit values and produce a 64-bit result. - -\subsection{Faster Multiplication by the ``Comba'' Method} -MARK,COMBA - -One of the huge drawbacks of the ``baseline'' algorithms is that at the $O(n^2)$ level the carry must be computed and propagated upwards. This -makes the nested loop very sequential and hard to unroll and implement in parallel. The ``Comba'' \cite{COMBA} method is named after little known -(\textit{in cryptographic venues}) Paul G. Comba who described a method of implementing fast multipliers that do not require nested -carry fixup operations. As an interesting aside it seems that Paul Barrett describes a similar technique in -his 1986 paper \cite{BARRETT} written five years before. - -At the heart of the Comba technique is once again the long-hand algorithm. Except in this case a slight twist is placed on how -the columns of the result are produced. In the standard long-hand algorithm rows of products are produced then added together to form the -final result. In the baseline algorithm the columns are added together after each iteration to get the result instantaneously. - -In the Comba algorithm the columns of the result are produced entirely independently of each other. That is at the $O(n^2)$ level a -simple multiplication and addition step is performed. The carries of the columns are propagated after the nested loop to reduce the amount -of work requiored. Succintly the first step of the algorithm is to compute the product vector $\vec x$ as follows. - -\begin{equation} -\vec x_n = \sum_{i+j = n} a_ib_j, \forall n \in \lbrace 0, 1, 2, \ldots, i + j \rbrace -\end{equation} - -Where $\vec x_n$ is the $n'th$ column of the output vector. Consider the following example which computes the vector $\vec x$ for the multiplication -of $576$ and $241$. - -\newpage\begin{figure}[here] -\begin{small} -\begin{center} -\begin{tabular}{|c|c|c|c|c|c|} - \hline & & 5 & 7 & 6 & First Input\\ - \hline $\times$ & & 2 & 4 & 1 & Second Input\\ -\hline & & $1 \cdot 5 = 5$ & $1 \cdot 7 = 7$ & $1 \cdot 6 = 6$ & First pass \\ - & $4 \cdot 5 = 20$ & $4 \cdot 7+5=33$ & $4 \cdot 6+7=31$ & 6 & Second pass \\ - $2 \cdot 5 = 10$ & $2 \cdot 7 + 20 = 34$ & $2 \cdot 6+33=45$ & 31 & 6 & Third pass \\ -\hline 10 & 34 & 45 & 31 & 6 & Final Result \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Comba Multiplication Diagram} -\end{figure} - -At this point the vector $x = \left < 10, 34, 45, 31, 6 \right >$ is the result of the first step of the Comba multipler. -Now the columns must be fixed by propagating the carry upwards. The resultant vector will have one extra dimension over the input vector which is -congruent to adding a leading zero digit. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{Comba Fixup}. \\ -\textbf{Input}. Vector $\vec x$ of dimension $k$ \\ -\textbf{Output}. Vector $\vec x$ such that the carries have been propagated. \\ -\hline \\ -1. for $n$ from $0$ to $k - 1$ do \\ -\hspace{3mm}1.1 $\vec x_{n+1} \leftarrow \vec x_{n+1} + \lfloor \vec x_{n}/\beta \rfloor$ \\ -\hspace{3mm}1.2 $\vec x_{n} \leftarrow \vec x_{n} \mbox{ (mod }\beta\mbox{)}$ \\ -2. Return($\vec x$). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm Comba Fixup} -\end{figure} - -With that algorithm and $k = 5$ and $\beta = 10$ the following vector is produced $\vec x= \left < 1, 3, 8, 8, 1, 6 \right >$. In this case -$241 \cdot 576$ is in fact $138816$ and the procedure succeeded. If the algorithm is correct and as will be demonstrated shortly more -efficient than the baseline algorithm why not simply always use this algorithm? - -\subsubsection{Column Weight.} -At the nested $O(n^2)$ level the Comba method adds the product of two single precision variables to each column of the output -independently. A serious obstacle is if the carry is lost, due to lack of precision before the algorithm has a chance to fix -the carries. For example, in the multiplication of two three-digit numbers the third column of output will be the sum of -three single precision multiplications. If the precision of the accumulator for the output digits is less then $3 \cdot (\beta - 1)^2$ then -an overflow can occur and the carry information will be lost. For any $m$ and $n$ digit inputs the maximum weight of any column is -min$(m, n)$ which is fairly obvious. - -The maximum number of terms in any column of a product is known as the ``column weight'' and strictly governs when the algorithm can be used. Recall -from earlier that a double precision type has $\alpha$ bits of resolution and a single precision digit has $lg(\beta)$ bits of precision. Given these -two quantities we must not violate the following - -\begin{equation} -k \cdot \left (\beta - 1 \right )^2 < 2^{\alpha} -\end{equation} - -Which reduces to - -\begin{equation} -k \cdot \left ( \beta^2 - 2\beta + 1 \right ) < 2^{\alpha} -\end{equation} - -Let $\rho = lg(\beta)$ represent the number of bits in a single precision digit. By further re-arrangement of the equation the final solution is -found. - -\begin{equation} -k < {{2^{\alpha}} \over {\left (2^{2\rho} - 2^{\rho + 1} + 1 \right )}} -\end{equation} - -The defaults for LibTomMath are $\beta = 2^{28}$ and $\alpha = 2^{64}$ which means that $k$ is bounded by $k < 257$. In this configuration -the smaller input may not have more than $256$ digits if the Comba method is to be used. This is quite satisfactory for most applications since -$256$ digits would allow for numbers in the range of $0 \le x < 2^{7168}$ which, is much larger than most public key cryptographic algorithms require. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{fast\_s\_mp\_mul\_digs}. \\ -\textbf{Input}. mp\_int $a$, mp\_int $b$ and an integer $digs$ \\ -\textbf{Output}. $c \leftarrow \vert a \vert \cdot \vert b \vert \mbox{ (mod }\beta^{digs}\mbox{)}$. \\ -\hline \\ -Place an array of \textbf{MP\_WARRAY} double precision digits named $\hat W$ on the stack. \\ -1. If $c.alloc < digs$ then grow $c$ to $digs$ digits. (\textit{mp\_grow}) \\ -2. If step 1 failed return(\textit{MP\_MEM}).\\ -\\ -Zero the temporary array $\hat W$. \\ -3. for $n$ from $0$ to $digs - 1$ do \\ -\hspace{3mm}3.1 $\hat W_n \leftarrow 0$ \\ -\\ -Compute the columns. \\ -4. for $ix$ from $0$ to $a.used - 1$ do \\ -\hspace{3mm}4.1 $pb \leftarrow \mbox{min}(b.used, digs - ix)$ \\ -\hspace{3mm}4.2 If $pb < 1$ then goto step 5. \\ -\hspace{3mm}4.3 for $iy$ from $0$ to $pb - 1$ do \\ -\hspace{6mm}4.3.1 $\hat W_{ix+iy} \leftarrow \hat W_{ix+iy} + a_{ix}b_{iy}$ \\ -\\ -Propagate the carries upwards. \\ -5. $oldused \leftarrow c.used$ \\ -6. $c.used \leftarrow digs$ \\ -7. If $digs > 1$ then do \\ -\hspace{3mm}7.1. for $ix$ from $1$ to $digs - 1$ do \\ -\hspace{6mm}7.1.1 $\hat W_{ix} \leftarrow \hat W_{ix} + \lfloor \hat W_{ix-1} / \beta \rfloor$ \\ -\hspace{6mm}7.1.2 $c_{ix - 1} \leftarrow \hat W_{ix - 1} \mbox{ (mod }\beta\mbox{)}$ \\ -8. else do \\ -\hspace{3mm}8.1 $ix \leftarrow 0$ \\ -9. $c_{ix} \leftarrow \hat W_{ix} \mbox{ (mod }\beta\mbox{)}$ \\ -\\ -Zero excess digits. \\ -10. If $digs < oldused$ then do \\ -\hspace{3mm}10.1 for $n$ from $digs$ to $oldused - 1$ do \\ -\hspace{6mm}10.1.1 $c_n \leftarrow 0$ \\ -11. Clamp excessive digits of $c$. (\textit{mp\_clamp}) \\ -12. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm fast\_s\_mp\_mul\_digs} -\label{fig:COMBAMULT} -\end{figure} - -\textbf{Algorithm fast\_s\_mp\_mul\_digs.} -This algorithm performs the unsigned multiplication of $a$ and $b$ using the Comba method limited to $digs$ digits of precision. The algorithm -essentially peforms the same calculation as algorithm s\_mp\_mul\_digs, just much faster. - -The array $\hat W$ is meant to be on the stack when the algorithm is used. The size of the array does not change which is ideal. Note also that -unlike algorithm s\_mp\_mul\_digs no temporary mp\_int is required since the result is calculated directly in $\hat W$. - -The $O(n^2)$ loop on step four is where the Comba method's advantages begin to show through in comparison to the baseline algorithm. The lack of -a carry variable or propagation in this loop allows the loop to be performed with only single precision multiplication and additions. Now that each -iteration of the inner loop can be performed independent of the others the inner loop can be performed with a high level of parallelism. - -To measure the benefits of the Comba method over the baseline method consider the number of operations that are required. If the -cost in terms of time of a multiply and addition is $p$ and the cost of a carry propagation is $q$ then a baseline multiplication would require -$O \left ((p + q)n^2 \right )$ time to multiply two $n$-digit numbers. The Comba method requires only $O(pn^2 + qn)$ time, however in practice, -the speed increase is actually much more. With $O(n)$ space the algorithm can be reduced to $O(pn + qn)$ time by implementing the $n$ multiply -and addition operations in the nested loop in parallel. - -EXAM,bn_fast_s_mp_mul_digs.c - -The memset on line @47,memset@ clears the initial $\hat W$ array to zero in a single step. Like the slower baseline multiplication -implementation a series of aliases (\textit{lines @67, tmpx@, @70, tmpy@ and @75,_W@}) are used to simplify the inner $O(n^2)$ loop. -In this case a new alias $\_\hat W$ has been added which refers to the double precision columns offset by $ix$ in each pass. - -The inner loop on lines @83,for@, @84,mp_word@ and @85,}@ is where the algorithm will spend the majority of the time, which is why it has been -stripped to the bones of any extra baggage\footnote{Hence the pointer aliases.}. On x86 processors the multiplication and additions amount to at the -very least five instructions (\textit{two loads, two additions, one multiply}) while on the ARMv4 processors they amount to only three -(\textit{one load, one store, one multiply-add}). For both of the x86 and ARMv4 processors the GCC compiler performs a good job at unrolling the loop -and scheduling the instructions so there are very few dependency stalls. - -In theory the difference between the baseline and comba algorithms is a mere $O(qn)$ time difference. However, in the $O(n^2)$ nested loop of the -baseline method there are dependency stalls as the algorithm must wait for the multiplier to finish before propagating the carry to the next -digit. As a result fewer of the often multiple execution units\footnote{The AMD Athlon has three execution units and the Intel P4 has four.} can -be simultaneously used. - -\subsection{Polynomial Basis Multiplication} -To break the $O(n^2)$ barrier in multiplication requires a completely different look at integer multiplication. In the following algorithms -the use of polynomial basis representation for two integers $a$ and $b$ as $f(x) = \sum_{i=0}^{n} a_i x^i$ and -$g(x) = \sum_{i=0}^{n} b_i x^i$ respectively, is required. In this system both $f(x)$ and $g(x)$ have $n + 1$ terms and are of the $n$'th degree. - -The product $a \cdot b \equiv f(x)g(x)$ is the polynomial $W(x) = \sum_{i=0}^{2n} w_i x^i$. The coefficients $w_i$ will -directly yield the desired product when $\beta$ is substituted for $x$. The direct solution to solve for the $2n + 1$ coefficients -requires $O(n^2)$ time and would in practice be slower than the Comba technique. - -However, numerical analysis theory indicates that only $2n + 1$ distinct points in $W(x)$ are required to determine the values of the $2n + 1$ unknown -coefficients. This means by finding $\zeta_y = W(y)$ for $2n + 1$ small values of $y$ the coefficients of $W(x)$ can be found with -Gaussian elimination. This technique is also occasionally refered to as the \textit{interpolation technique} (\textit{references please...}) since in -effect an interpolation based on $2n + 1$ points will yield a polynomial equivalent to $W(x)$. - -The coefficients of the polynomial $W(x)$ are unknown which makes finding $W(y)$ for any value of $y$ impossible. However, since -$W(x) = f(x)g(x)$ the equivalent $\zeta_y = f(y) g(y)$ can be used in its place. The benefit of this technique stems from the -fact that $f(y)$ and $g(y)$ are much smaller than either $a$ or $b$ respectively. As a result finding the $2n + 1$ relations required -by multiplying $f(y)g(y)$ involves multiplying integers that are much smaller than either of the inputs. - -When picking points to gather relations there are always three obvious points to choose, $y = 0, 1$ and $ \infty$. The $\zeta_0$ term -is simply the product $W(0) = w_0 = a_0 \cdot b_0$. The $\zeta_1$ term is the product -$W(1) = \left (\sum_{i = 0}^{n} a_i \right ) \left (\sum_{i = 0}^{n} b_i \right )$. The third point $\zeta_{\infty}$ is less obvious but rather -simple to explain. The $2n + 1$'th coefficient of $W(x)$ is numerically equivalent to the most significant column in an integer multiplication. -The point at $\infty$ is used symbolically to represent the most significant column, that is $W(\infty) = w_{2n} = a_nb_n$. Note that the -points at $y = 0$ and $\infty$ yield the coefficients $w_0$ and $w_{2n}$ directly. - -If more points are required they should be of small values and powers of two such as $2^q$ and the related \textit{mirror points} -$\left (2^q \right )^{2n} \cdot \zeta_{2^{-q}}$ for small values of $q$. The term ``mirror point'' stems from the fact that -$\left (2^q \right )^{2n} \cdot \zeta_{2^{-q}}$ can be calculated in the exact opposite fashion as $\zeta_{2^q}$. For -example, when $n = 2$ and $q = 1$ then following two equations are equivalent to the point $\zeta_{2}$ and its mirror. - -\begin{eqnarray} -\zeta_{2} = f(2)g(2) = (4a_2 + 2a_1 + a_0)(4b_2 + 2b_1 + b_0) \nonumber \\ -16 \cdot \zeta_{1 \over 2} = 4f({1\over 2}) \cdot 4g({1 \over 2}) = (a_2 + 2a_1 + 4a_0)(b_2 + 2b_1 + 4b_0) -\end{eqnarray} - -Using such points will allow the values of $f(y)$ and $g(y)$ to be independently calculated using only left shifts. For example, when $n = 2$ the -polynomial $f(2^q)$ is equal to $2^q((2^qa_2) + a_1) + a_0$. This technique of polynomial representation is known as Horner's method. - -As a general rule of the algorithm when the inputs are split into $n$ parts each there are $2n - 1$ multiplications. Each multiplication is of -multiplicands that have $n$ times fewer digits than the inputs. The asymptotic running time of this algorithm is -$O \left ( k^{lg_n(2n - 1)} \right )$ for $k$ digit inputs (\textit{assuming they have the same number of digits}). Figure~\ref{fig:exponent} -summarizes the exponents for various values of $n$. - -\begin{figure} -\begin{center} -\begin{tabular}{|c|c|c|} -\hline \textbf{Split into $n$ Parts} & \textbf{Exponent} & \textbf{Notes}\\ -\hline $2$ & $1.584962501$ & This is Karatsuba Multiplication. \\ -\hline $3$ & $1.464973520$ & This is Toom-Cook Multiplication. \\ -\hline $4$ & $1.403677461$ &\\ -\hline $5$ & $1.365212389$ &\\ -\hline $10$ & $1.278753601$ &\\ -\hline $100$ & $1.149426538$ &\\ -\hline $1000$ & $1.100270931$ &\\ -\hline $10000$ & $1.075252070$ &\\ -\hline -\end{tabular} -\end{center} -\caption{Asymptotic Running Time of Polynomial Basis Multiplication} -\label{fig:exponent} -\end{figure} - -At first it may seem like a good idea to choose $n = 1000$ since the exponent is approximately $1.1$. However, the overhead -of solving for the 2001 terms of $W(x)$ will certainly consume any savings the algorithm could offer for all but exceedingly large -numbers. - -\subsubsection{Cutoff Point} -The polynomial basis multiplication algorithms all require fewer single precision multiplications than a straight Comba approach. However, -the algorithms incur an overhead (\textit{at the $O(n)$ work level}) since they require a system of equations to be solved. This makes the -polynomial basis approach more costly to use with small inputs. - -Let $m$ represent the number of digits in the multiplicands (\textit{assume both multiplicands have the same number of digits}). There exists a -point $y$ such that when $m < y$ the polynomial basis algorithms are more costly than Comba, when $m = y$ they are roughly the same cost and -when $m > y$ the Comba methods are slower than the polynomial basis algorithms. - -The exact location of $y$ depends on several key architectural elements of the computer platform in question. - -\begin{enumerate} -\item The ratio of clock cycles for single precision multiplication versus other simpler operations such as addition, shifting, etc. For example -on the AMD Athlon the ratio is roughly $17 : 1$ while on the Intel P4 it is $29 : 1$. The higher the ratio in favour of multiplication the lower -the cutoff point $y$ will be. - -\item The complexity of the linear system of equations (\textit{for the coefficients of $W(x)$}) is. Generally speaking as the number of splits -grows the complexity grows substantially. Ideally solving the system will only involve addition, subtraction and shifting of integers. This -directly reflects on the ratio previous mentioned. - -\item To a lesser extent memory bandwidth and function call overheads. Provided the values are in the processor cache this is less of an -influence over the cutoff point. - -\end{enumerate} - -A clean cutoff point separation occurs when a point $y$ is found such that all of the cutoff point conditions are met. For example, if the point -is too low then there will be values of $m$ such that $m > y$ and the Comba method is still faster. Finding the cutoff points is fairly simple when -a high resolution timer is available. - -\subsection{Karatsuba Multiplication} -Karatsuba \cite{KARA} multiplication when originally proposed in 1962 was among the first set of algorithms to break the $O(n^2)$ barrier for -general purpose multiplication. Given two polynomial basis representations $f(x) = ax + b$ and $g(x) = cx + d$, Karatsuba proved with -light algebra \cite{KARAP} that the following polynomial is equivalent to multiplication of the two integers the polynomials represent. - -\begin{equation} -f(x) \cdot g(x) = acx^2 + ((a - b)(c - d) + ac + bd)x + bd -\end{equation} - -Using the observation that $ac$ and $bd$ could be re-used only three half sized multiplications would be required to produce the product. Applying -this algorithm recursively, the work factor becomes $O(n^{lg(3)})$ which is substantially better than the work factor $O(n^2)$ of the Comba technique. It turns -out what Karatsuba did not know or at least did not publish was that this is simply polynomial basis multiplication with the points -$\zeta_0$, $\zeta_{\infty}$ and $-\zeta_{-1}$. Consider the resultant system of equations. - -\begin{center} -\begin{tabular}{rcrcrcrc} -$\zeta_{0}$ & $=$ & & & & & $w_0$ \\ -$-\zeta_{-1}$ & $=$ & $-w_2$ & $+$ & $w_1$ & $-$ & $w_0$ \\ -$\zeta_{\infty}$ & $=$ & $w_2$ & & & & \\ -\end{tabular} -\end{center} - -By adding the first and last equation to the equation in the middle the term $w_1$ can be isolated and all three coefficients solved for. The simplicity -of this system of equations has made Karatsuba fairly popular. In fact the cutoff point is often fairly low\footnote{With LibTomMath 0.18 it is 70 and 109 digits for the Intel P4 and AMD Athlon respectively.} -making it an ideal algorithm to speed up certain public key cryptosystems such as RSA and Diffie-Hellman. It is worth noting that the point -$\zeta_1$ could be substituted for $-\zeta_{-1}$. In this case the first and third row are subtracted instead of added to the second row. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_karatsuba\_mul}. \\ -\textbf{Input}. mp\_int $a$ and mp\_int $b$ \\ -\textbf{Output}. $c \leftarrow \vert a \vert \cdot \vert b \vert$ \\ -\hline \\ -1. Init the following mp\_int variables: $x0$, $x1$, $y0$, $y1$, $t1$, $x0y0$, $x1y1$.\\ -2. If step 2 failed then return(\textit{MP\_MEM}). \\ -\\ -Split the input. e.g. $a = x1 \cdot \beta^B + x0$ \\ -3. $B \leftarrow \mbox{min}(a.used, b.used)/2$ \\ -4. $x0 \leftarrow a \mbox{ (mod }\beta^B\mbox{)}$ (\textit{mp\_mod\_2d}) \\ -5. $y0 \leftarrow b \mbox{ (mod }\beta^B\mbox{)}$ \\ -6. $x1 \leftarrow \lfloor a / \beta^B \rfloor$ (\textit{mp\_rshd}) \\ -7. $y1 \leftarrow \lfloor b / \beta^B \rfloor$ \\ -\\ -Calculate the three products. \\ -8. $x0y0 \leftarrow x0 \cdot y0$ (\textit{mp\_mul}) \\ -9. $x1y1 \leftarrow x1 \cdot y1$ \\ -10. $t1 \leftarrow x1 - x0$ (\textit{mp\_sub}) \\ -11. $x0 \leftarrow y1 - y0$ \\ -12. $t1 \leftarrow t1 \cdot x0$ \\ -\\ -Calculate the middle term. \\ -13. $x0 \leftarrow x0y0 + x1y1$ \\ -14. $t1 \leftarrow x0 - t1$ \\ -\\ -Calculate the final product. \\ -15. $t1 \leftarrow t1 \cdot \beta^B$ (\textit{mp\_lshd}) \\ -16. $x1y1 \leftarrow x1y1 \cdot \beta^{2B}$ \\ -17. $t1 \leftarrow x0y0 + t1$ \\ -18. $c \leftarrow t1 + x1y1$ \\ -19. Clear all of the temporary variables. \\ -20. Return(\textit{MP\_OKAY}).\\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_karatsuba\_mul} -\end{figure} - -\textbf{Algorithm mp\_karatsuba\_mul.} -This algorithm computes the unsigned product of two inputs using the Karatsuba multiplication algorithm. It is loosely based on the description -from Knuth \cite[pp. 294-295]{TAOCPV2}. - -\index{radix point} -In order to split the two inputs into their respective halves, a suitable \textit{radix point} must be chosen. The radix point chosen must -be used for both of the inputs meaning that it must be smaller than the smallest input. Step 3 chooses the radix point $B$ as half of the -smallest input \textbf{used} count. After the radix point is chosen the inputs are split into lower and upper halves. Step 4 and 5 -compute the lower halves. Step 6 and 7 computer the upper halves. - -After the halves have been computed the three intermediate half-size products must be computed. Step 8 and 9 compute the trivial products -$x0 \cdot y0$ and $x1 \cdot y1$. The mp\_int $x0$ is used as a temporary variable after $x1 - x0$ has been computed. By using $x0$ instead -of an additional temporary variable, the algorithm can avoid an addition memory allocation operation. - -The remaining steps 13 through 18 compute the Karatsuba polynomial through a variety of digit shifting and addition operations. - -EXAM,bn_mp_karatsuba_mul.c - -The new coding element in this routine, not seen in previous routines, is the usage of goto statements. The conventional -wisdom is that goto statements should be avoided. This is generally true, however when every single function call can fail, it makes sense -to handle error recovery with a single piece of code. Lines @61,if@ to @75,if@ handle initializing all of the temporary variables -required. Note how each of the if statements goes to a different label in case of failure. This allows the routine to correctly free only -the temporaries that have been successfully allocated so far. - -The temporary variables are all initialized using the mp\_init\_size routine since they are expected to be large. This saves the -additional reallocation that would have been necessary. Also $x0$, $x1$, $y0$ and $y1$ have to be able to hold at least their respective -number of digits for the next section of code. - -The first algebraic portion of the algorithm is to split the two inputs into their halves. However, instead of using mp\_mod\_2d and mp\_rshd -to extract the halves, the respective code has been placed inline within the body of the function. To initialize the halves, the \textbf{used} and -\textbf{sign} members are copied first. The first for loop on line @98,for@ copies the lower halves. Since they are both the same magnitude it -is simpler to calculate both lower halves in a single loop. The for loop on lines @104,for@ and @109,for@ calculate the upper halves $x1$ and -$y1$ respectively. - -By inlining the calculation of the halves, the Karatsuba multiplier has a slightly lower overhead and can be used for smaller magnitude inputs. - -When line @152,err@ is reached, the algorithm has completed succesfully. The ``error status'' variable $err$ is set to \textbf{MP\_OKAY} so that -the same code that handles errors can be used to clear the temporary variables and return. - -\subsection{Toom-Cook $3$-Way Multiplication} -Toom-Cook $3$-Way \cite{TOOM} multiplication is essentially the polynomial basis algorithm for $n = 3$ except that the points are -chosen such that $\zeta$ is easy to compute and the resulting system of equations easy to reduce. Here, the points $\zeta_{0}$, -$16 \cdot \zeta_{1 \over 2}$, $\zeta_1$, $\zeta_2$ and $\zeta_{\infty}$ make up the five required points to solve for the coefficients -of the $W(x)$. - -With the five relations that Toom-Cook specifies, the following system of equations is formed. - -\begin{center} -\begin{tabular}{rcrcrcrcrcr} -$\zeta_0$ & $=$ & $0w_4$ & $+$ & $0w_3$ & $+$ & $0w_2$ & $+$ & $0w_1$ & $+$ & $1w_0$ \\ -$16 \cdot \zeta_{1 \over 2}$ & $=$ & $1w_4$ & $+$ & $2w_3$ & $+$ & $4w_2$ & $+$ & $8w_1$ & $+$ & $16w_0$ \\ -$\zeta_1$ & $=$ & $1w_4$ & $+$ & $1w_3$ & $+$ & $1w_2$ & $+$ & $1w_1$ & $+$ & $1w_0$ \\ -$\zeta_2$ & $=$ & $16w_4$ & $+$ & $8w_3$ & $+$ & $4w_2$ & $+$ & $2w_1$ & $+$ & $1w_0$ \\ -$\zeta_{\infty}$ & $=$ & $1w_4$ & $+$ & $0w_3$ & $+$ & $0w_2$ & $+$ & $0w_1$ & $+$ & $0w_0$ \\ -\end{tabular} -\end{center} - -A trivial solution to this matrix requires $12$ subtractions, two multiplications by a small power of two, two divisions by a small power -of two, two divisions by three and one multiplication by three. All of these $19$ sub-operations require less than quadratic time, meaning that -the algorithm can be faster than a baseline multiplication. However, the greater complexity of this algorithm places the cutoff point -(\textbf{TOOM\_MUL\_CUTOFF}) where Toom-Cook becomes more efficient much higher than the Karatsuba cutoff point. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_toom\_mul}. \\ -\textbf{Input}. mp\_int $a$ and mp\_int $b$ \\ -\textbf{Output}. $c \leftarrow a \cdot b $ \\ -\hline \\ -Split $a$ and $b$ into three pieces. E.g. $a = a_2 \beta^{2k} + a_1 \beta^{k} + a_0$ \\ -1. $k \leftarrow \lfloor \mbox{min}(a.used, b.used) / 3 \rfloor$ \\ -2. $a_0 \leftarrow a \mbox{ (mod }\beta^{k}\mbox{)}$ \\ -3. $a_1 \leftarrow \lfloor a / \beta^k \rfloor$, $a_1 \leftarrow a_1 \mbox{ (mod }\beta^{k}\mbox{)}$ \\ -4. $a_2 \leftarrow \lfloor a / \beta^{2k} \rfloor$, $a_2 \leftarrow a_2 \mbox{ (mod }\beta^{k}\mbox{)}$ \\ -5. $b_0 \leftarrow a \mbox{ (mod }\beta^{k}\mbox{)}$ \\ -6. $b_1 \leftarrow \lfloor a / \beta^k \rfloor$, $b_1 \leftarrow b_1 \mbox{ (mod }\beta^{k}\mbox{)}$ \\ -7. $b_2 \leftarrow \lfloor a / \beta^{2k} \rfloor$, $b_2 \leftarrow b_2 \mbox{ (mod }\beta^{k}\mbox{)}$ \\ -\\ -Find the five equations for $w_0, w_1, ..., w_4$. \\ -8. $w_0 \leftarrow a_0 \cdot b_0$ \\ -9. $w_4 \leftarrow a_2 \cdot b_2$ \\ -10. $tmp_1 \leftarrow 2 \cdot a_0$, $tmp_1 \leftarrow a_1 + tmp_1$, $tmp_1 \leftarrow 2 \cdot tmp_1$, $tmp_1 \leftarrow tmp_1 + a_2$ \\ -11. $tmp_2 \leftarrow 2 \cdot b_0$, $tmp_2 \leftarrow b_1 + tmp_2$, $tmp_2 \leftarrow 2 \cdot tmp_2$, $tmp_2 \leftarrow tmp_2 + b_2$ \\ -12. $w_1 \leftarrow tmp_1 \cdot tmp_2$ \\ -13. $tmp_1 \leftarrow 2 \cdot a_2$, $tmp_1 \leftarrow a_1 + tmp_1$, $tmp_1 \leftarrow 2 \cdot tmp_1$, $tmp_1 \leftarrow tmp_1 + a_0$ \\ -14. $tmp_2 \leftarrow 2 \cdot b_2$, $tmp_2 \leftarrow b_1 + tmp_2$, $tmp_2 \leftarrow 2 \cdot tmp_2$, $tmp_2 \leftarrow tmp_2 + b_0$ \\ -15. $w_3 \leftarrow tmp_1 \cdot tmp_2$ \\ -16. $tmp_1 \leftarrow a_0 + a_1$, $tmp_1 \leftarrow tmp_1 + a_2$, $tmp_2 \leftarrow b_0 + b_1$, $tmp_2 \leftarrow tmp_2 + b_2$ \\ -17. $w_2 \leftarrow tmp_1 \cdot tmp_2$ \\ -\\ -Continued on the next page.\\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_toom\_mul} -\end{figure} - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_toom\_mul} (continued). \\ -\textbf{Input}. mp\_int $a$ and mp\_int $b$ \\ -\textbf{Output}. $c \leftarrow a \cdot b $ \\ -\hline \\ -Now solve the system of equations. \\ -18. $w_1 \leftarrow w_4 - w_1$, $w_3 \leftarrow w_3 - w_0$ \\ -19. $w_1 \leftarrow \lfloor w_1 / 2 \rfloor$, $w_3 \leftarrow \lfloor w_3 / 2 \rfloor$ \\ -20. $w_2 \leftarrow w_2 - w_0$, $w_2 \leftarrow w_2 - w_4$ \\ -21. $w_1 \leftarrow w_1 - w_2$, $w_3 \leftarrow w_3 - w_2$ \\ -22. $tmp_1 \leftarrow 8 \cdot w_0$, $w_1 \leftarrow w_1 - tmp_1$, $tmp_1 \leftarrow 8 \cdot w_4$, $w_3 \leftarrow w_3 - tmp_1$ \\ -23. $w_2 \leftarrow 3 \cdot w_2$, $w_2 \leftarrow w_2 - w_1$, $w_2 \leftarrow w_2 - w_3$ \\ -24. $w_1 \leftarrow w_1 - w_2$, $w_3 \leftarrow w_3 - w_2$ \\ -25. $w_1 \leftarrow \lfloor w_1 / 3 \rfloor, w_3 \leftarrow \lfloor w_3 / 3 \rfloor$ \\ -\\ -Now substitute $\beta^k$ for $x$ by shifting $w_0, w_1, ..., w_4$. \\ -26. for $n$ from $1$ to $4$ do \\ -\hspace{3mm}26.1 $w_n \leftarrow w_n \cdot \beta^{nk}$ \\ -27. $c \leftarrow w_0 + w_1$, $c \leftarrow c + w_2$, $c \leftarrow c + w_3$, $c \leftarrow c + w_4$ \\ -28. Return(\textit{MP\_OKAY}) \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_toom\_mul (continued)} -\end{figure} - -\textbf{Algorithm mp\_toom\_mul.} -This algorithm computes the product of two mp\_int variables $a$ and $b$ using the Toom-Cook approach. Compared to the Karatsuba multiplication, this -algorithm has a lower asymptotic running time of approximately $O(n^{1.464})$ but at an obvious cost in overhead. In this -description, several statements have been compounded to save space. The intention is that the statements are executed from left to right across -any given step. - -The two inputs $a$ and $b$ are first split into three $k$-digit integers $a_0, a_1, a_2$ and $b_0, b_1, b_2$ respectively. From these smaller -integers the coefficients of the polynomial basis representations $f(x)$ and $g(x)$ are known and can be used to find the relations required. - -The first two relations $w_0$ and $w_4$ are the points $\zeta_{0}$ and $\zeta_{\infty}$ respectively. The relation $w_1, w_2$ and $w_3$ correspond -to the points $16 \cdot \zeta_{1 \over 2}, \zeta_{2}$ and $\zeta_{1}$ respectively. These are found using logical shifts to independently find -$f(y)$ and $g(y)$ which significantly speeds up the algorithm. - -After the five relations $w_0, w_1, \ldots, w_4$ have been computed, the system they represent must be solved in order for the unknown coefficients -$w_1, w_2$ and $w_3$ to be isolated. The steps 18 through 25 perform the system reduction required as previously described. Each step of -the reduction represents the comparable matrix operation that would be performed had this been performed by pencil. For example, step 18 indicates -that row $1$ must be subtracted from row $4$ and simultaneously row $0$ subtracted from row $3$. - -Once the coeffients have been isolated, the polynomial $W(x) = \sum_{i=0}^{2n} w_i x^i$ is known. By substituting $\beta^{k}$ for $x$, the integer -result $a \cdot b$ is produced. - -EXAM,bn_mp_toom_mul.c - --- Comments to be added during editing phase. - -\subsection{Signed Multiplication} -Now that algorithms to handle multiplications of every useful dimensions have been developed, a rather simple finishing touch is required. So far all -of the multiplication algorithms have been unsigned multiplications which leaves only a signed multiplication algorithm to be established. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_mul}. \\ -\textbf{Input}. mp\_int $a$ and mp\_int $b$ \\ -\textbf{Output}. $c \leftarrow a \cdot b$ \\ -\hline \\ -1. If $a.sign = b.sign$ then \\ -\hspace{3mm}1.1 $sign = MP\_ZPOS$ \\ -2. else \\ -\hspace{3mm}2.1 $sign = MP\_ZNEG$ \\ -3. If min$(a.used, b.used) \ge TOOM\_MUL\_CUTOFF$ then \\ -\hspace{3mm}3.1 $c \leftarrow a \cdot b$ using algorithm mp\_toom\_mul \\ -4. else if min$(a.used, b.used) \ge KARATSUBA\_MUL\_CUTOFF$ then \\ -\hspace{3mm}4.1 $c \leftarrow a \cdot b$ using algorithm mp\_karatsuba\_mul \\ -5. else \\ -\hspace{3mm}5.1 $digs \leftarrow a.used + b.used + 1$ \\ -\hspace{3mm}5.2 If $digs < MP\_ARRAY$ and min$(a.used, b.used) \le \delta$ then \\ -\hspace{6mm}5.2.1 $c \leftarrow a \cdot b \mbox{ (mod }\beta^{digs}\mbox{)}$ using algorithm fast\_s\_mp\_mul\_digs. \\ -\hspace{3mm}5.3 else \\ -\hspace{6mm}5.3.1 $c \leftarrow a \cdot b \mbox{ (mod }\beta^{digs}\mbox{)}$ using algorithm s\_mp\_mul\_digs. \\ -6. $c.sign \leftarrow sign$ \\ -7. Return the result of the unsigned multiplication performed. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_mul} -\end{figure} - -\textbf{Algorithm mp\_mul.} -This algorithm performs the signed multiplication of two inputs. It will make use of any of the three unsigned multiplication algorithms -available when the input is of appropriate size. The \textbf{sign} of the result is not set until the end of the algorithm since algorithm -s\_mp\_mul\_digs will clear it. - -EXAM,bn_mp_mul.c - -The implementation is rather simplistic and is not particularly noteworthy. Line @22,?@ computes the sign of the result using the ``?'' -operator from the C programming language. Line @37,<<@ computes $\delta$ using the fact that $1 << k$ is equal to $2^k$. - -\section{Squaring} - -Squaring is a special case of multiplication where both multiplicands are equal. At first it may seem like there is no significant optimization -available but in fact there is. Consider the multiplication of $576$ against $241$. In total there will be nine single precision multiplications -performed which are $1\cdot 6$, $1 \cdot 7$, $1 \cdot 5$, $4 \cdot 6$, $4 \cdot 7$, $4 \cdot 5$, $2 \cdot 6$, $2 \cdot 7$ and $2 \cdot 5$. Now consider -the multiplication of $123$ against $123$. The nine products are $3 \cdot 3$, $3 \cdot 2$, $3 \cdot 1$, $2 \cdot 3$, $2 \cdot 2$, $2 \cdot 1$, -$1 \cdot 3$, $1 \cdot 2$ and $1 \cdot 1$. On closer inspection some of the products are equivalent. For example, $3 \cdot 2 = 2 \cdot 3$ -and $3 \cdot 1 = 1 \cdot 3$. - -For any $n$-digit input, there are ${{\left (n^2 + n \right)}\over 2}$ possible unique single precision multiplications required compared to the $n^2$ -required for multiplication. The following diagram gives an example of the operations required. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{ccccc|c} -&&1&2&3&\\ -$\times$ &&1&2&3&\\ -\hline && $3 \cdot 1$ & $3 \cdot 2$ & $3 \cdot 3$ & Row 0\\ - & $2 \cdot 1$ & $2 \cdot 2$ & $2 \cdot 3$ && Row 1 \\ - $1 \cdot 1$ & $1 \cdot 2$ & $1 \cdot 3$ &&& Row 2 \\ -\end{tabular} -\end{center} -\caption{Squaring Optimization Diagram} -\end{figure} - -MARK,SQUARE -Starting from zero and numbering the columns from right to left a very simple pattern becomes obvious. For the purposes of this discussion let $x$ -represent the number being squared. The first observation is that in row $k$ the $2k$'th column of the product has a $\left (x_k \right)^2$ term in it. - -The second observation is that every column $j$ in row $k$ where $j \ne 2k$ is part of a double product. Every non-square term of a column will -appear twice hence the name ``double product''. Every odd column is made up entirely of double products. In fact every column is made up of double -products and at most one square (\textit{see the exercise section}). - -The third and final observation is that for row $k$ the first unique non-square term, that is, one that hasn't already appeared in an earlier row, -occurs at column $2k + 1$. For example, on row $1$ of the previous squaring, column one is part of the double product with column one from row zero. -Column two of row one is a square and column three is the first unique column. - -\subsection{The Baseline Squaring Algorithm} -The baseline squaring algorithm is meant to be a catch-all squaring algorithm. It will handle any of the input sizes that the faster routines -will not handle. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{s\_mp\_sqr}. \\ -\textbf{Input}. mp\_int $a$ \\ -\textbf{Output}. $b \leftarrow a^2$ \\ -\hline \\ -1. Init a temporary mp\_int of at least $2 \cdot a.used +1$ digits. (\textit{mp\_init\_size}) \\ -2. If step 1 failed return(\textit{MP\_MEM}) \\ -3. $t.used \leftarrow 2 \cdot a.used + 1$ \\ -4. For $ix$ from 0 to $a.used - 1$ do \\ -\hspace{3mm}Calculate the square. \\ -\hspace{3mm}4.1 $\hat r \leftarrow t_{2ix} + \left (a_{ix} \right )^2$ \\ -\hspace{3mm}4.2 $t_{2ix} \leftarrow \hat r \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{3mm}Calculate the double products after the square. \\ -\hspace{3mm}4.3 $u \leftarrow \lfloor \hat r / \beta \rfloor$ \\ -\hspace{3mm}4.4 For $iy$ from $ix + 1$ to $a.used - 1$ do \\ -\hspace{6mm}4.4.1 $\hat r \leftarrow 2 \cdot a_{ix}a_{iy} + t_{ix + iy} + u$ \\ -\hspace{6mm}4.4.2 $t_{ix + iy} \leftarrow \hat r \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{6mm}4.4.3 $u \leftarrow \lfloor \hat r / \beta \rfloor$ \\ -\hspace{3mm}Set the last carry. \\ -\hspace{3mm}4.5 While $u > 0$ do \\ -\hspace{6mm}4.5.1 $iy \leftarrow iy + 1$ \\ -\hspace{6mm}4.5.2 $\hat r \leftarrow t_{ix + iy} + u$ \\ -\hspace{6mm}4.5.3 $t_{ix + iy} \leftarrow \hat r \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{6mm}4.5.4 $u \leftarrow \lfloor \hat r / \beta \rfloor$ \\ -5. Clamp excess digits of $t$. (\textit{mp\_clamp}) \\ -6. Exchange $b$ and $t$. \\ -7. Clear $t$ (\textit{mp\_clear}) \\ -8. Return(\textit{MP\_OKAY}) \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm s\_mp\_sqr} -\end{figure} - -\textbf{Algorithm s\_mp\_sqr.} -This algorithm computes the square of an input using the three observations on squaring. It is based fairly faithfully on algorithm 14.16 of HAC -\cite[pp.596-597]{HAC}. Similar to algorithm s\_mp\_mul\_digs, a temporary mp\_int is allocated to hold the result of the squaring. This allows the -destination mp\_int to be the same as the source mp\_int. - -The outer loop of this algorithm begins on step 4. It is best to think of the outer loop as walking down the rows of the partial results, while -the inner loop computes the columns of the partial result. Step 4.1 and 4.2 compute the square term for each row, and step 4.3 and 4.4 propagate -the carry and compute the double products. - -The requirement that a mp\_word be able to represent the range $0 \le x < 2 \beta^2$ arises from this -very algorithm. The product $a_{ix}a_{iy}$ will lie in the range $0 \le x \le \beta^2 - 2\beta + 1$ which is obviously less than $\beta^2$ meaning that -when it is multiplied by two, it can be properly represented by a mp\_word. - -Similar to algorithm s\_mp\_mul\_digs, after every pass of the inner loop, the destination is correctly set to the sum of all of the partial -results calculated so far. This involves expensive carry propagation which will be eliminated in the next algorithm. - -EXAM,bn_s_mp_sqr.c - -Inside the outer loop (\textit{see line @32,for@}) the square term is calculated on line @35,r =@. Line @42,>>@ extracts the carry from the square -term. Aliases for $a_{ix}$ and $t_{ix+iy}$ are initialized on lines @45,tmpx@ and @48,tmpt@ respectively. The doubling is performed using two -additions (\textit{see line @57,r + r@}) since it is usually faster than shifting,if not at least as fast. - -\subsection{Faster Squaring by the ``Comba'' Method} -A major drawback to the baseline method is the requirement for single precision shifting inside the $O(n^2)$ nested loop. Squaring has an additional -drawback that it must double the product inside the inner loop as well. As for multiplication, the Comba technique can be used to eliminate these -performance hazards. - -The first obvious solution is to make an array of mp\_words which will hold all of the columns. This will indeed eliminate all of the carry -propagation operations from the inner loop. However, the inner product must still be doubled $O(n^2)$ times. The solution stems from the simple fact -that $2a + 2b + 2c = 2(a + b + c)$. That is the sum of all of the double products is equal to double the sum of all the products. For example, -$ab + ba + ac + ca = 2ab + 2ac = 2(ab + ac)$. - -However, we cannot simply double all of the columns, since the squares appear only once per row. The most practical solution is to have two mp\_word -arrays. One array will hold the squares and the other array will hold the double products. With both arrays the doubling and carry propagation can be -moved to a $O(n)$ work level outside the $O(n^2)$ level. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{fast\_s\_mp\_sqr}. \\ -\textbf{Input}. mp\_int $a$ \\ -\textbf{Output}. $b \leftarrow a^2$ \\ -\hline \\ -Place two arrays of \textbf{MP\_WARRAY} mp\_words named $\hat W$ and $\hat {X}$ on the stack. \\ -1. If $b.alloc < 2a.used + 1$ then grow $b$ to $2a.used + 1$ digits. (\textit{mp\_grow}). \\ -2. If step 1 failed return(\textit{MP\_MEM}). \\ -3. for $ix$ from $0$ to $2a.used + 1$ do \\ -\hspace{3mm}3.1 $\hat W_{ix} \leftarrow 0$ \\ -\hspace{3mm}3.2 $\hat {X}_{ix} \leftarrow 0$ \\ -4. for $ix$ from $0$ to $a.used - 1$ do \\ -\hspace{3mm}Compute the square.\\ -\hspace{3mm}4.1 $\hat {X}_{ix+ix} \leftarrow \left ( a_ix \right )^2$ \\ -\\ -\hspace{3mm}Compute the double products.\\ -\hspace{3mm}4.2 for $iy$ from $ix + 1$ to $a.used - 1$ do \\ -\hspace{6mm}4.2.1 $\hat W_{ix+iy} \leftarrow \hat W_{ix+iy} + a_{ix}a_{iy}$ \\ -5. $oldused \leftarrow b.used$ \\ -6. $b.used \leftarrow 2a.used + 1$ \\ -\\ -Double the products and propagate the carries simultaneously. \\ -7. $\hat W_0 \leftarrow 2 \hat W_0 + \hat {X}_0$ \\ -8. for $ix$ from $1$ to $2a.used$ do \\ -\hspace{3mm}8.1 $\hat W_{ix} \leftarrow 2 \hat W_{ix} + \hat {X}_{ix}$ \\ -\hspace{3mm}8.2 $\hat W_{ix} \leftarrow \hat W_{ix} + \lfloor \hat W_{ix - 1} / \beta \rfloor$ \\ -\hspace{3mm}8.3 $b_{ix-1} \leftarrow W_{ix-1} \mbox{ (mod }\beta\mbox{)}$ \\ -9. $b_{2a.used} \leftarrow \hat W_{2a.used} \mbox{ (mod }\beta\mbox{)}$ \\ -10. if $2a.used + 1 < oldused$ then do \\ -\hspace{3mm}10.1 for $ix$ from $2a.used + 1$ to $oldused$ do \\ -\hspace{6mm}10.1.1 $b_{ix} \leftarrow 0$ \\ -11. Clamp excess digits from $b$. (\textit{mp\_clamp}) \\ -12. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm fast\_s\_mp\_sqr} -\end{figure} - -\textbf{Algorithm fast\_s\_mp\_sqr.} -This algorithm computes the square of an input using the Comba technique. It is designed to be a replacement for algorithm s\_mp\_sqr when -the number of input digits is less than \textbf{MP\_WARRAY} and less than $\delta \over 2$. - -This routine requires two arrays of mp\_words to be placed on the stack. The first array $\hat W$ will hold the double products and the second -array $\hat X$ will hold the squares. Though only at most $MP\_WARRAY \over 2$ words of $\hat X$ are used, it has proven faster on most -processors to simply make it a full size array. - -The loop on step 3 will zero the two arrays to prepare them for the squaring step. Step 4.1 computes the squares of the product. Note how -it simply assigns the value into the $\hat X$ array. The nested loop on step 4.2 computes the doubles of the products. This loop -computes the sum of the products for each column. They are not doubled until later. - -After the squaring loop, the products stored in $\hat W$ musted be doubled and the carries propagated forwards. It makes sense to do both -operations at the same time. The expression $\hat W_{ix} \leftarrow 2 \hat W_{ix} + \hat {X}_{ix}$ computes the sum of the double product and the -squares in place. - -EXAM,bn_fast_s_mp_sqr.c - --- Write something deep and insightful later, Tom. - -\subsection{Polynomial Basis Squaring} -The same algorithm that performs optimal polynomial basis multiplication can be used to perform polynomial basis squaring. The minor exception -is that $\zeta_y = f(y)g(y)$ is actually equivalent to $\zeta_y = f(y)^2$ since $f(y) = g(y)$. Instead of performing $2n + 1$ -multiplications to find the $\zeta$ relations, squaring operations are performed instead. - -\subsection{Karatsuba Squaring} -Let $f(x) = ax + b$ represent the polynomial basis representation of a number to square. -Let $h(x) = \left ( f(x) \right )^2$ represent the square of the polynomial. The Karatsuba equation can be modified to square a -number with the following equation. - -\begin{equation} -h(x) = a^2x^2 + \left (a^2 + b^2 - (a - b)^2 \right )x + b^2 -\end{equation} - -Upon closer inspection this equation only requires the calculation of three half-sized squares: $a^2$, $b^2$ and $(a - b)^2$. As in -Karatsuba multiplication, this algorithm can be applied recursively on the input and will achieve an asymptotic running time of -$O \left ( n^{lg(3)} \right )$. - -You might ask yourself, if the asymptotic time of Karatsuba squaring and multiplication is the same, why not simply use the multiplication algorithm -instead? The answer to this arises from the cutoff point for squaring. As in multiplication there exists a cutoff point, at which the -time required for a Comba based squaring and a Karatsuba based squaring meet. Due to the overhead inherent in the Karatsuba method, the cutoff -point is fairly high. For example, on an AMD Athlon XP processor with $\beta = 2^{28}$, the cutoff point is around 127 digits. - -Consider squaring a 200 digit number with this technique. It will be split into two 100 digit halves which are subsequently squared. -The 100 digit halves will not be squared using Karatsuba, but instead using the faster Comba based squaring algorithm. If Karatsuba multiplication -were used instead, the 100 digit numbers would be squared with a slower Comba based multiplication. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_karatsuba\_sqr}. \\ -\textbf{Input}. mp\_int $a$ \\ -\textbf{Output}. $b \leftarrow a^2$ \\ -\hline \\ -1. Initialize the following temporary mp\_ints: $x0$, $x1$, $t1$, $t2$, $x0x0$ and $x1x1$. \\ -2. If any of the initializations on step 1 failed return(\textit{MP\_MEM}). \\ -\\ -Split the input. e.g. $a = x1\beta^B + x0$ \\ -3. $B \leftarrow \lfloor a.used / 2 \rfloor$ \\ -4. $x0 \leftarrow a \mbox{ (mod }\beta^B\mbox{)}$ (\textit{mp\_mod\_2d}) \\ -5. $x1 \leftarrow \lfloor a / \beta^B \rfloor$ (\textit{mp\_lshd}) \\ -\\ -Calculate the three squares. \\ -6. $x0x0 \leftarrow x0^2$ (\textit{mp\_sqr}) \\ -7. $x1x1 \leftarrow x1^2$ \\ -8. $t1 \leftarrow x1 - x0$ (\textit{mp\_sub}) \\ -9. $t1 \leftarrow t1^2$ \\ -\\ -Compute the middle term. \\ -10. $t2 \leftarrow x0x0 + x1x1$ (\textit{s\_mp\_add}) \\ -11. $t1 \leftarrow t2 - t1$ \\ -\\ -Compute final product. \\ -12. $t1 \leftarrow t1\beta^B$ (\textit{mp\_lshd}) \\ -13. $x1x1 \leftarrow x1x1\beta^{2B}$ \\ -14. $t1 \leftarrow t1 + x0x0$ \\ -15. $b \leftarrow t1 + x1x1$ \\ -16. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_karatsuba\_sqr} -\end{figure} - -\textbf{Algorithm mp\_karatsuba\_sqr.} -This algorithm computes the square of an input $a$ using the Karatsuba technique. This algorithm is very similar to the Karatsuba based -multiplication algorithm with the exception that the three half-size multiplications have been replaced with three half-size squarings. - -The radix point for squaring is simply placed exactly in the middle of the digits when the input has an odd number of digits, otherwise it is -placed just below the middle. Step 3, 4 and 5 compute the two halves required using $B$ -as the radix point. The first two squares in steps 6 and 7 are rather straightforward while the last square is of a more compact form. - -By expanding $\left (x1 - x0 \right )^2$, the $x1^2$ and $x0^2$ terms in the middle disappear, that is $x1^2 + x0^2 - (x1 - x0)^2 = 2 \cdot x0 \cdot x1$. -Now if $5n$ single precision additions and a squaring of $n$-digits is faster than multiplying two $n$-digit numbers and doubling then -this method is faster. Assuming no further recursions occur, the difference can be estimated with the following inequality. - -Let $p$ represent the cost of a single precision addition and $q$ the cost of a single precision multiplication both in terms of time\footnote{Or -machine clock cycles.}. - -\begin{equation} -5pn +{{q(n^2 + n)} \over 2} \le pn + qn^2 -\end{equation} - -For example, on an AMD Athlon XP processor $p = {1 \over 3}$ and $q = 6$. This implies that the following inequality should hold. -\begin{center} -\begin{tabular}{rcl} -${5n \over 3} + 3n^2 + 3n$ & $<$ & ${n \over 3} + 6n^2$ \\ -${5 \over 3} + 3n + 3$ & $<$ & ${1 \over 3} + 6n$ \\ -${13 \over 9}$ & $<$ & $n$ \\ -\end{tabular} -\end{center} - -This results in a cutoff point around $n = 2$. As a consequence it is actually faster to compute the middle term the ``long way'' on processors -where multiplication is substantially slower\footnote{On the Athlon there is a 1:17 ratio between clock cycles for addition and multiplication. On -the Intel P4 processor this ratio is 1:29 making this method even more beneficial. The only common exception is the ARMv4 processor which has a -ratio of 1:7. } than simpler operations such as addition. - -EXAM,bn_mp_karatsuba_sqr.c - -This implementation is largely based on the implementation of algorithm mp\_karatsuba\_mul. It uses the same inline style to copy and -shift the input into the two halves. The loop from line @54,{@ to line @70,}@ has been modified since only one input exists. The \textbf{used} -count of both $x0$ and $x1$ is fixed up and $x0$ is clamped before the calculations begin. At this point $x1$ and $x0$ are valid equivalents -to the respective halves as if mp\_rshd and mp\_mod\_2d had been used. - -By inlining the copy and shift operations the cutoff point for Karatsuba multiplication can be lowered. On the Athlon the cutoff point -is exactly at the point where Comba squaring can no longer be used (\textit{128 digits}). On slower processors such as the Intel P4 -it is actually below the Comba limit (\textit{at 110 digits}). - -This routine uses the same error trap coding style as mp\_karatsuba\_sqr. As the temporary variables are initialized errors are redirected to -the error trap higher up. If the algorithm completes without error the error code is set to \textbf{MP\_OKAY} and mp\_clears are executed normally. - -\textit{Last paragraph sucks. re-write! -- Tom} - -\subsection{Toom-Cook Squaring} -The Toom-Cook squaring algorithm mp\_toom\_sqr is heavily based on the algorithm mp\_toom\_mul with the exception that squarings are used -instead of multiplication to find the five relations.. The reader is encouraged to read the description of the latter algorithm and try to -derive their own Toom-Cook squaring algorithm. - -\subsection{High Level Squaring} -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_sqr}. \\ -\textbf{Input}. mp\_int $a$ \\ -\textbf{Output}. $b \leftarrow a^2$ \\ -\hline \\ -1. If $a.used \ge TOOM\_SQR\_CUTOFF$ then \\ -\hspace{3mm}1.1 $b \leftarrow a^2$ using algorithm mp\_toom\_sqr \\ -2. else if $a.used \ge KARATSUBA\_SQR\_CUTOFF$ then \\ -\hspace{3mm}2.1 $b \leftarrow a^2$ using algorithm mp\_karatsuba\_sqr \\ -3. else \\ -\hspace{3mm}3.1 $digs \leftarrow a.used + b.used + 1$ \\ -\hspace{3mm}3.2 If $digs < MP\_ARRAY$ and $a.used \le \delta$ then \\ -\hspace{6mm}3.2.1 $b \leftarrow a^2$ using algorithm fast\_s\_mp\_sqr. \\ -\hspace{3mm}3.3 else \\ -\hspace{6mm}3.3.1 $b \leftarrow a^2$ using algorithm s\_mp\_sqr. \\ -4. $b.sign \leftarrow MP\_ZPOS$ \\ -5. Return the result of the unsigned squaring performed. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_sqr} -\end{figure} - -\textbf{Algorithm mp\_sqr.} -This algorithm computes the square of the input using one of four different algorithms. If the input is very large and has at least -\textbf{TOOM\_SQR\_CUTOFF} or \textbf{KARATSUBA\_SQR\_CUTOFF} digits then either the Toom-Cook or the Karatsuba Squaring algorithm is used. If -neither of the polynomial basis algorithms should be used then either the Comba or baseline algorithm is used. - -EXAM,bn_mp_sqr.c - -\section*{Exercises} -\begin{tabular}{cl} -$\left [ 3 \right ] $ & Devise an efficient algorithm for selection of the radix point to handle inputs \\ - & that have different number of digits in Karatsuba multiplication. \\ - & \\ -$\left [ 3 \right ] $ & In ~SQUARE~ the fact that every column of a squaring is made up \\ - & of double products and at most one square is stated. Prove this statement. \\ - & \\ -$\left [ 2 \right ] $ & In the Comba squaring algorithm half of the $\hat X$ variables are not used. \\ - & Revise algorithm fast\_s\_mp\_sqr to shrink the $\hat X$ array. \\ - & \\ -$\left [ 3 \right ] $ & Prove the equation for Karatsuba squaring. \\ - & \\ -$\left [ 1 \right ] $ & Prove that Karatsuba squaring requires $O \left (n^{lg(3)} \right )$ time. \\ - & \\ -$\left [ 2 \right ] $ & Determine the minimal ratio between addition and multiplication clock cycles \\ - & required for equation $6.7$ to be true. \\ - & \\ -\end{tabular} - -\chapter{Modular Reduction} -MARK,REDUCTION -\section{Basics of Modular Reduction} -\index{modular residue} -Modular reduction is an operation that arises quite often within public key cryptography algorithms and various number theoretic algorithms, -such as factoring. Modular reduction algorithms are the third class of algorithms of the ``multipliers'' set. A number $a$ is said to be reduced -modulo another number $b$ by finding the remainder of the division $a/b$. - -Modular reduction is equivalent to solving for $r$ in the following equation. $a = bq + r$ where $q = \lfloor a/b \rfloor$. The result -$r$ is said to be ``congruent to $a$ modulo $b$'' which is also written as $r \equiv a \mbox{ (mod }b\mbox{)}$. In other vernacular $r$ is known as the -``modular residue'' which leads to ``quadratic residue''\footnote{That's fancy talk for $b \equiv a^2 \mbox{ (mod }p\mbox{)}$.} and -other forms of residues. - -\index{modulus} -Modular reductions are normally used to form finite groups such as fields and rings. For example, in the RSA public key algorithm \cite{RSAPAPER} -two private primes $p$ and $q$ are chosen which when multiplied $n = pq$ forms a composite modulus. When operations such as multiplication and -squaring are performed on units of the ring $\Z_n$ a finite multiplicative sub-group is formed. - -Modular reductions have a variety of other useful properties. For example, a number $x$ is a square if and only if it is a quadratic -residue modulo a prime. With a finite set of primes $B = \left < p_0, p_1, \ldots, p_n \right >$ a quick test for whether $x$ is square or not can -be performed\footnote{Provided none of the primes from $B$ divide $x$.}. Consider the figure~\ref{fig:QR} with the candiate $x = 955621$ a simple -set of modular reductions modulo $3, 5, \ldots, 11$ may detect whether $x$ is a square or not. In this case $955621 \equiv 7 \mbox{ (mod }11\mbox{)}$ -and since $7$ is not a quadratic residue modulo $11$ the number $955621$ is not a square. - -\begin{figure} -\begin{center} -\begin{tabular}{|c|l|} -\hline \textbf{Prime} & \textbf{Quadratic Residues} \\ -\hline $3$ & $1$ \\ -\hline $5$ & $1, 4$ \\ -\hline $7$ & $1, 2, 4$ \\ -\hline $11$ & $1, 3, 4, 5, 9$ \\ -\hline -\end{tabular} -\end{center} -\caption{Quadratic Residues for primes less than $13$} -\label{fig:QR} -\end{figure} - -The most common usage for performance driven modular reductions is in modular exponentiation algorithms. That is to compute -$d = a^b \mbox{ (mod }c\mbox{)}$ as fast as possible. As will be discussed in the subsequent chapter there exists fast algorithms for computing -modular exponentiations without having to perform (\textit{in this example}) $b - 1$ multiplications. These algorithms will produce partial -results in the range $0 \le x < c^2$ which can be taken advantage of to create several efficient algorithms. - -\section{The Barrett Reduction} -The Barrett reduction algorithm \cite{BARRETT} was inspired by fast division algorithms which multiply by the reciprocal to emulate -division. Barretts observation was that the residue $c$ of $a$ modulo $b$ is equal to - -\begin{equation} -c = a - b \cdot \lfloor a/b \rfloor -\end{equation} - -Since algorithms such as modular exponentiation would be using the same modulus extensively, typical DSP intuition would indicate the next step -would be to replace $a/b$ by a multiplication by the reciprocal. However, DSP intuition on its own will not work as these numbers are considerably -larger than the precision of common DSP floating point data types. It would take another common optimization to optimize the algorithm. - -\subsection{Fixed Point Arithmetic} -The trick used to optimize the above equation is based on a technique of emulating floating point data types with fixed precision integers. Fixed -point arithmetic would vastly popularlize the ``3d-shooter'' genre of games in the mid 1990s when floating point units were fairly slow. The idea behind -fixed point arithmetic is to take a normal $k$-bit integer data type and break it into $p$-bit integer and a $q$-bit fraction part -(\textit{where $p+q = k$}). - -In this system a $k$-bit integer $n$ would actually represent $n/2^q$. For example, with $q = 4$ the integer $n = 37$ would actually represent the -value $2.3125$. To multiply two fixed point numbers the integers are multiplied using traditional arithmetic and subsequently normalized. For example, -with $q = 4$ to multiply the integers $9$ and $5$ they must be converted to fixed point first by multiplying by $2^q$. Let $a = 9(2^q)$ -represent the fixed point representation of $9$ and $b = 5(2^q)$ represent the fixed point representation of $5$. The product $ab$ is equal to -$45(2^{2q})$ which when normalized produces $45(2^q)$. - -Using fixed point arithmetic division can be easily achieved by multiplying by the reciprocal. If $2^q$ is equivalent to one than $2^q/b$ is -equivalent to $1/b$ using real arithmetic. Using this fact dividing an integer $a$ by another integer $b$ can be achieved with the following -expression. - -\begin{equation} -\lfloor (a \cdot (\lfloor 2^q / b \rfloor))/2^q \rfloor -\end{equation} - -The precision of the division is proportional to the value of $q$. If the divisor $b$ is used frequently as is the case with -modular exponentiation pre-computing $2^q/b$ will allow a division to be performed with a multiplication and a right shift. Both operations -are considerably faster than division on most processors. - -Consider dividing $19$ by $5$. The correct result is $\lfloor 19/5 \rfloor = 3$. With $q = 3$ the reciprocal is $\lfloor 2^q/5 \rfloor = 1$ which -leads to a product of $19$ which when divided by $2^q$ produces $2$. However, with $q = 4$ the reciprocal is $\lfloor 2^q/5 \rfloor = 3$ and -the result of the emulated division is $\lfloor 3 \cdot 19 / 2^q \rfloor = 3$ which is correct. - -Plugging this form of divison into the original equation the following modular residue equation arises. - -\begin{equation} -c = a - b \cdot \lfloor (a \cdot (\lfloor 2^q / b \rfloor))/2^q \rfloor -\end{equation} - -Using the notation from \cite{BARRETT} the value of $\lfloor 2^q / b \rfloor$ will be represented by the $\mu$ symbol. Using the $\mu$ -variable also helps re-inforce the idea that it is meant to be computed once and re-used. - -\begin{equation} -c = a - b \cdot \lfloor (a \cdot \mu)/2^q \rfloor -\end{equation} - -Provided that $2^q > b^2$ this algorithm will produce a quotient that is either exactly correct or off by a value of one. Let $n$ represent -the number of digits in $b$. This algorithm requires approximately $2n^2$ single precision multiplications to produce the quotient and -another $n^2$ single precision multiplications to find the residue. In total $3n^2$ single precision multiplications are required to -reduce the number. - -For example, if $b = 1179677$ and $q = 41$ ($2^q > b^2$), then the reciprocal $\mu$ is equal to $\lfloor 2^q / b \rfloor = 1864089$. Consider reducing -$a = 180388626447$ modulo $b$ using the above reduction equation. The quotient using the new formula is $\lfloor (a \cdot \mu) / 2^q \rfloor = 152913$. -By subtracting $152913b$ from $a$ the correct residue $a \equiv 677346 \mbox{ (mod }b\mbox{)}$ is found. - -\subsection{Choosing a Radix Point} -Using the fixed point representation a modular reduction can be performed with $3n^2$ single precision multiplications. If that were the best -that could be achieved a full division might as well be used in its place. The key to optimizing the reduction is to reduce the precision of -the initial multiplication that finds the quotient. - -Let $a$ represent the number of which the residue is sought. Let $b$ represent the modulus used to find the residue. Let $m$ represent -the number of digits in $b$. For the purposes of this discussion we will assume that the number of digits in $a$ is $2m$. Dividing $a$ by -$b$ is the same as dividing a $2m$ digit integer by a $m$ digit integer. Digits below the $m - 1$'th digit of $a$ will contribute at most a value -of $1$ to the quotient because $\beta^k < b$ for any $0 \le k \le m - 1$. - -Since those digits do not contribute much to the quotient the observation is that they might as well be zero. However, if the digits -``might as well be zero'' they might as well not be there in the first place. Let $q_0 = \lfloor a/\beta^{m-1} \rfloor$ represent the input -with the zeroes trimmed. Now the modular reduction is trimmed to the almost equivalent equation - -\begin{equation} -c = a - b \cdot \lfloor (q_0 \cdot \mu) / \beta^{m+1} \rfloor -\end{equation} - -Note that the original divisor $2^q$ has been replaced with $\beta^{m+1}$. Also note that the exponent on the divisor when added to the amount $q_0$ -was shifted by equals $2m$. If the optimization had not been performed the divisor would have the exponent $2m$ so in the end the exponents -do ``add up''. Using the above equation the quotient $\lfloor (q_0 \cdot \mu) / \beta^{m+1} \rfloor$ can be off from the true quotient by at most -two implying that $0 \le a - b \cdot \lfloor (q_0 \cdot \mu) / \beta^{m+1} \rfloor < 3b$. By first subtracting $b$ times the quotient and then -conditionally subtracting $b$ once or twice the residue is found. - -The quotient is now found using $(m + 1)(m) = m^2 + m$ single precision multiplications and the residue with an additional $m^2$ single -precision multiplications. In total $2m^2 + m$ single precision multiplications are required which is considerably faster than the original -attempt. - -For example, let $\beta = 10$ represent the radix of the digits. Let $b = 9999$ represent the modulus which implies $m = 4$. Let $a = 99929878$ -represent the value of which the residue is desired. In this case $q = 8$ since $10^7 < 9999^2$ meaning that $\mu = \lfloor \beta^{q}/b \rfloor = 10001$. -With the new observation the multiplicand for the quotient is equal to $q_0 = \lfloor a / \beta^{m - 1} \rfloor = 99929$. The quotient is then -$\lfloor (q_0 \cdot \mu) / \beta^{m+1} \rfloor = 9993$. Subtracting $9993b$ from $a$ and the correct residue $a \equiv 9871 \mbox{ (mod }b\mbox{)}$ -is found. - -\subsection{Trimming the Quotient} -So far the reduction algorithm has been optimized from $3m^2$ single precision multiplications down to $2m^2 + m$ single precision multiplications. As -it stands now the algorithm is already fairly fast compared to a full integer division algorithm. However, there is still room for -optimization. - -After the first multiplication inside the quotient ($q_0 \cdot \mu$) the value is shifted right by $m + 1$ places effectively nullifying the lower -half of the product. It would be nice to be able to remove those digits from the product to effectively cut down the number of single precision -multiplications. If the number of digits in the modulus $m$ is far less than $\beta$ a full product is not required for the algorithm to work properly. -In fact the lower $m - 2$ digits will not affect the upper half of the product at all and do not need to be computed. - -The value of $\mu$ is a $m$-digit number and $q_0$ is a $m + 1$ digit number. Using a full multiplier $(m + 1)(m) = m^2 + m$ single precision -multiplications would be required. Using a multiplier that will only produce digits at and above the $m - 1$'th digit reduces the number -of single precision multiplications to ${m^2 + m} \over 2$ single precision multiplications. - -\subsection{Trimming the Residue} -After the quotient has been calculated it is used to reduce the input. As previously noted the algorithm is not exact and it can be off by a small -multiple of the modulus, that is $0 \le a - b \cdot \lfloor (q_0 \cdot \mu) / \beta^{m+1} \rfloor < 3b$. If $b$ is $m$ digits than the -result of reduction equation is a value of at most $m + 1$ digits (\textit{provided $3 < \beta$}) implying that the upper $m - 1$ digits are -implicitly zero. - -The next optimization arises from this very fact. Instead of computing $b \cdot \lfloor (q_0 \cdot \mu) / \beta^{m+1} \rfloor$ using a full -$O(m^2)$ multiplication algorithm only the lower $m+1$ digits of the product have to be computed. Similarly the value of $a$ can -be reduced modulo $\beta^{m+1}$ before the multiple of $b$ is subtracted which simplifes the subtraction as well. A multiplication that produces -only the lower $m+1$ digits requires ${m^2 + 3m - 2} \over 2$ single precision multiplications. - -With both optimizations in place the algorithm is the algorithm Barrett proposed. It requires $m^2 + 2m - 1$ single precision multiplications which -is considerably faster than the straightforward $3m^2$ method. - -\subsection{The Barrett Algorithm} -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_reduce}. \\ -\textbf{Input}. mp\_int $a$, mp\_int $b$ and $\mu = \lfloor \beta^{2m}/b \rfloor$ $(0 \le a < b^2, b > 1)$ \\ -\textbf{Output}. $c \leftarrow a \mbox{ (mod }b\mbox{)}$ \\ -\hline \\ -Let $m$ represent the number of digits in $b$. \\ -1. Make a copy of $a$ and store it in $q$. (\textit{mp\_init\_copy}) \\ -2. $q \leftarrow \lfloor q / \beta^{m - 1} \rfloor$ (\textit{mp\_rshd}) \\ -\\ -Produce the quotient. \\ -3. $q \leftarrow q \cdot \mu$ (\textit{note: only produce digits at or above $m-1$}) \\ -4. $q \leftarrow \lfloor q / \beta^{m + 1} \rfloor$ \\ -\\ -Subtract the multiple of modulus from the input. \\ -5. $c \leftarrow a \mbox{ (mod }\beta^{m+1}\mbox{)}$ (\textit{mp\_mod\_2d}) \\ -6. $q \leftarrow q \cdot b \mbox{ (mod }\beta^{m+1}\mbox{)}$ (\textit{s\_mp\_mul\_digs}) \\ -7. $c \leftarrow c - q$ (\textit{mp\_sub}) \\ -\\ -Add $\beta^{m+1}$ if a carry occured. \\ -8. If $c < 0$ then (\textit{mp\_cmp\_d}) \\ -\hspace{3mm}8.1 $q \leftarrow 1$ (\textit{mp\_set}) \\ -\hspace{3mm}8.2 $q \leftarrow q \cdot \beta^{m+1}$ (\textit{mp\_lshd}) \\ -\hspace{3mm}8.3 $c \leftarrow c + q$ \\ -\\ -Now subtract the modulus if the residue is too large (e.g. quotient too small). \\ -9. While $c \ge b$ do (\textit{mp\_cmp}) \\ -\hspace{3mm}9.1 $c \leftarrow c - b$ \\ -10. Clear $q$. \\ -11. Return(\textit{MP\_OKAY}) \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_reduce} -\end{figure} - -\textbf{Algorithm mp\_reduce.} -This algorithm will reduce the input $a$ modulo $b$ in place using the Barrett algorithm. It is loosely based on algorithm 14.42 of HAC -\cite[pp. 602]{HAC} which is based on the paper from Paul Barrett \cite{BARRETT}. The algorithm has several restrictions and assumptions which must be adhered to -for the algorithm to work. - -First the modulus $b$ is assumed to be positive and greater than one. If the modulus were less than or equal to one than subtracting -a multiple of it would either accomplish nothing or actually enlarge the input. The input $a$ must be in the range $0 \le a < b^2$ in order -for the quotient to have enough precision. Technically the algorithm will still work if $a \ge b^2$ but it will take much longer to finish. The -value of $\mu$ is passed as an argument to this algorithm and is assumed to be setup before the algorithm is used. - -Recall that the multiplication for the quotient on step 3 must only produce digits at or above the $m-1$'th position. An algorithm called -$s\_mp\_mul\_high\_digs$ which has not been presented is used to accomplish this task. This optimal algorithm can only be used if the number -of digits in $b$ is very much smaller than $\beta$. - -After the multiple of the modulus has been subtracted from $a$ the residue must be fixed up in case its negative. While it is known that -$a \ge b \cdot \lfloor (q_0 \cdot \mu) / \beta^{m+1} \rfloor$ only the lower $m+1$ digits are being used to compute the residue. In this case -the invariant $\beta^{m+1}$ must be added to the residue to make it positive again. - -The while loop at step 9 will subtract $b$ until the residue is less than $b$. If the algorithm is performed correctly this step is only -performed upto two times. However, if $a \ge b^2$ than it will iterate substantially more times than it should. - -EXAM,bn_mp_reduce.c - -The first multiplication that determines the quotient can be performed by only producing the digits from $m - 1$ and up. This essentially halves -the number of single precision multiplications required. However, the optimization is only safe if $\beta$ is much larger than the number of digits -in the modulus. In the source code this is evaluated on lines @36,if@ to @44,}@ where algorithm s\_mp\_mul\_high\_digs is used when it is -safe to do so. - -\subsection{The Barrett Setup Algorithm} -In order to use algorithm mp\_reduce the value of $\mu$ must be calculated in advance. Ideally this value should be computed once and stored for -future use so that the Barrett algorithm can be used without delay. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_reduce\_setup}. \\ -\textbf{Input}. mp\_int $a$ ($a > 1$) \\ -\textbf{Output}. $\mu \leftarrow \lfloor \beta^{2m}/a \rfloor$ \\ -\hline \\ -1. $\mu \leftarrow 2^{2 \cdot lg(\beta) \cdot m}$ (\textit{mp\_2expt}) \\ -2. $\mu \leftarrow \lfloor \mu / b \rfloor$ (\textit{mp\_div}) \\ -3. Return(\textit{MP\_OKAY}) \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_reduce\_setup} -\end{figure} - -\textbf{Algorithm mp\_reduce\_setup.} -This algorithm computes the reciprocal $\mu$ required for Barrett reduction. First $\beta^{2m}$ is calculated as $2^{2 \cdot lg(\beta) \cdot m}$ which -is equivalent and much faster. The final value is computed by taking the integer quotient of $\lfloor \mu / b \rfloor$. - -EXAM,bn_mp_reduce_setup.c - -This simple routine calculates the reciprocal $\mu$ required by Barrett reduction. Note the extended usage of algorithm mp\_div where the variable -which would received the remainder is passed as NULL. As will be discussed in ~DIVISION~ the division routine allows both the quotient and the -remainder to be passed as NULL meaning to ignore the value. - -\section{The Montgomery Reduction} -Montgomery reduction\footnote{Thanks to Niels Ferguson for his insightful explanation of the algorithm.} \cite{MONT} is by far the most interesting -form of reduction in common use. It computes a modular residue which is not actually equal to the residue of the input yet instead equal to a -residue times a constant. However, as perplexing as this may sound the algorithm is relatively simple and very efficient. - -Throughout this entire section the variable $n$ will represent the modulus used to form the residue. As will be discussed shortly the value of -$n$ must be odd. The variable $x$ will represent the quantity of which the residue is sought. Similar to the Barrett algorithm the input -is restricted to $0 \le x < n^2$. To begin the description some simple number theory facts must be established. - -\textbf{Fact 1.} Adding $n$ to $x$ does not change the residue since in effect it adds one to the quotient $\lfloor x / n \rfloor$. Another way -to explain this is that $n$ (\textit{or multiples of $n$}) is congruent to zero modulo $n$. Adding zero will not change the value of the residue. - -\textbf{Fact 2.} If $x$ is even then performing a division by two in $\Z$ is congruent to $x \cdot 2^{-1} \mbox{ (mod }n\mbox{)}$. Actually -this is an application of the fact that if $x$ is evenly divisible by any $k \in \Z$ then division in $\Z$ will be congruent to -multiplication by $k^{-1}$ modulo $n$. - -From these two simple facts the following simple algorithm can be derived. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{Montgomery Reduction}. \\ -\textbf{Input}. Integer $x$, $n$ and $k$ \\ -\textbf{Output}. $2^{-k}x \mbox{ (mod }n\mbox{)}$ \\ -\hline \\ -1. for $t$ from $1$ to $k$ do \\ -\hspace{3mm}1.1 If $x$ is odd then \\ -\hspace{6mm}1.1.1 $x \leftarrow x + n$ \\ -\hspace{3mm}1.2 $x \leftarrow x/2$ \\ -2. Return $x$. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm Montgomery Reduction} -\end{figure} - -The algorithm reduces the input one bit at a time using the two congruencies stated previously. Inside the loop $n$, which is odd, is -added to $x$ if $x$ is odd. This forces $x$ to be even which allows the division by two in $\Z$ to be congruent to a modular division by two. Since -$x$ is assumed to be initially much larger than $n$ the addition of $n$ will contribute an insignificant magnitude to $x$. Let $r$ represent the -final result of the Montgomery algorithm. If $k > lg(n)$ and $0 \le x < n^2$ then the final result is limited to -$0 \le r < \lfloor x/2^k \rfloor + n$. As a result at most a single subtraction is required to get the residue desired. - -\begin{figure}[here] -\begin{small} -\begin{center} -\begin{tabular}{|c|l|} -\hline \textbf{Step number ($t$)} & \textbf{Result ($x$)} \\ -\hline $1$ & $x + n = 5812$, $x/2 = 2906$ \\ -\hline $2$ & $x/2 = 1453$ \\ -\hline $3$ & $x + n = 1710$, $x/2 = 855$ \\ -\hline $4$ & $x + n = 1112$, $x/2 = 556$ \\ -\hline $5$ & $x/2 = 278$ \\ -\hline $6$ & $x/2 = 139$ \\ -\hline $7$ & $x + n = 396$, $x/2 = 198$ \\ -\hline $8$ & $x/2 = 99$ \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Example of Montgomery Reduction (I)} -\label{fig:MONT1} -\end{figure} - -Consider the example in figure~\ref{fig:MONT1} which reduces $x = 5555$ modulo $n = 257$ when $k = 8$. The final result $r = 99$ which is actually -$2^{-8} \cdot 5555 \mbox{ (mod }257\mbox{)}$ can reveal the residue $x \equiv 158$ by multiplying by $2^8$ modulo $n$. - -Let $k = \lfloor lg(n) \rfloor + 1$ represent the number of bits in $n$. The current algorithm requires $2k^2$ single precision shifts -and $k^2$ single precision additions. At this rate the algorithm is most certainly slower than Barrett reduction and not terribly useful. -Fortunately there exists an alternative representation of the algorithm. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{Montgomery Reduction} (modified I). \\ -\textbf{Input}. Integer $x$, $n$ and $k$ \\ -\textbf{Output}. $2^{-k}x \mbox{ (mod }n\mbox{)}$ \\ -\hline \\ -1. for $t$ from $0$ to $k - 1$ do \\ -\hspace{3mm}1.1 If the $t$'th bit of $x$ is one then \\ -\hspace{6mm}1.1.1 $x \leftarrow x + 2^tn$ \\ -2. Return $x/2^k$. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm Montgomery Reduction (modified I)} -\end{figure} - -This algorithm is equivalent since $2^tn$ is a multiple of $n$ and the lower $k$ bits of $x$ are zero by step 2. The number of single -precision shifts has now been reduced from $2k^2$ to $k^2 + k$ which is only a small improvement. - -\begin{figure}[here] -\begin{small} -\begin{center} -\begin{tabular}{|c|l|} -\hline \textbf{Step number ($t$)} & \textbf{Result ($x$)} \\ -\hline $1$ & $x + 2^{0}n = 5812$ \\ -\hline $2$ & $5812$ \\ -\hline $3$ & $x + 2^{2}n = 6840$ \\ -\hline $4$ & $x + 2^{3}n = 8896$ \\ -\hline $5$ & $8896$ \\ -\hline $6$ & $8896$ \\ -\hline $7$ & $x + 2^{6}n = 25344$ \\ -\hline $8$ & $25344$ \\ -\hline -- & $x/2^k = 99$ \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Example of Montgomery Reduction (II)} -\label{fig:MONT2} -\end{figure} - -Figure~\ref{fig:MONT2} demonstrates the modified algorithm reducing $x = 4093$ modulo $n = 257$ with $k = 8$. -With this algorithm a single shift right at the end is the only right shift required to reduce the input instead of $k$ right shifts inside the -loop. Note that for the iterations $t = 2, 5, 6$ and $8$ where the result $x$ is not changed. In those iterations the $t$'th bit of $x$ is -zero and the appropriate multiple of $n$ does not need to be added to force the $t$'th bit of the result to zero. - -\subsection{Digit Based Montgomery Reduction} -Instead of computing the reduction on a bit-by-bit basis it is actually much faster to compute it on digit-by-digit basis. Consider the -previous algorithm re-written to compute the Montgomery reduction in this new fashion. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{Montgomery Reduction} (modified II). \\ -\textbf{Input}. Integer $x$, $n$ and $k$ \\ -\textbf{Output}. $\beta^{-k}x \mbox{ (mod }n\mbox{)}$ \\ -\hline \\ -1. for $t$ from $0$ to $k - 1$ do \\ -\hspace{3mm}1.1 $x \leftarrow x + \mu n \beta^t$ \\ -2. Return $x/\beta^k$. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm Montgomery Reduction (modified II)} -\end{figure} - -The value $\mu n \beta^t$ is a multiple of the modulus $n$ meaning that it will not change the residue. If the first digit of -the value $\mu n \beta^t$ equals the negative (modulo $\beta$) of the $t$'th digit of $x$ then the addition will result in a zero digit. This -problem breaks down to solving the following congruency. - -\begin{center} -\begin{tabular}{rcl} -$x_t + \mu n_0$ & $\equiv$ & $0 \mbox{ (mod }\beta\mbox{)}$ \\ -$\mu n_0$ & $\equiv$ & $-x_t \mbox{ (mod }\beta\mbox{)}$ \\ -$\mu$ & $\equiv$ & $-x_t/n_0 \mbox{ (mod }\beta\mbox{)}$ \\ -\end{tabular} -\end{center} - -In each iteration of the loop on step 1 a new value of $\mu$ must be calculated. The value of $-1/n_0 \mbox{ (mod }\beta\mbox{)}$ is used -extensively in this algorithm and should be precomputed. Let $\rho$ represent the negative of the modular inverse of $n_0$ modulo $\beta$. - -For example, let $\beta = 10$ represent the radix. Let $n = 17$ represent the modulus which implies $k = 2$ and $\rho \equiv 7$. Let $x = 33$ -represent the value to reduce. - -\newpage\begin{figure} -\begin{center} -\begin{tabular}{|c|c|c|} -\hline \textbf{Step ($t$)} & \textbf{Value of $x$} & \textbf{Value of $\mu$} \\ -\hline -- & $33$ & --\\ -\hline $0$ & $33 + \mu n = 50$ & $1$ \\ -\hline $1$ & $50 + \mu n \beta = 900$ & $5$ \\ -\hline -\end{tabular} -\end{center} -\caption{Example of Montgomery Reduction} -\end{figure} - -The final result $900$ is then divided by $\beta^k$ to produce the final result $9$. The first observation is that $9 \nequiv x \mbox{ (mod }n\mbox{)}$ -which implies the result is not the modular residue of $x$ modulo $n$. However, recall that the residue is actually multiplied by $\beta^{-k}$ in -the algorithm. To get the true residue the value must be multiplied by $\beta^k$. In this case $\beta^k \equiv 15 \mbox{ (mod }n\mbox{)}$ and -the correct residue is $9 \cdot 15 \equiv 16 \mbox{ (mod }n\mbox{)}$. - -\subsection{Baseline Montgomery Reduction} -The baseline Montgomery reduction algorithm will produce the residue for any size input. It is designed to be a catch-all algororithm for -Montgomery reductions. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_montgomery\_reduce}. \\ -\textbf{Input}. mp\_int $x$, mp\_int $n$ and a digit $\rho \equiv -1/n_0 \mbox{ (mod }n\mbox{)}$. \\ -\hspace{11.5mm}($0 \le x < n^2, n > 1, (n, \beta) = 1, \beta^k > n$) \\ -\textbf{Output}. $\beta^{-k}x \mbox{ (mod }n\mbox{)}$ \\ -\hline \\ -1. $digs \leftarrow 2n.used + 1$ \\ -2. If $digs < MP\_ARRAY$ and $m.used < \delta$ then \\ -\hspace{3mm}2.1 Use algorithm fast\_mp\_montgomery\_reduce instead. \\ -\\ -Setup $x$ for the reduction. \\ -3. If $x.alloc < digs$ then grow $x$ to $digs$ digits. \\ -4. $x.used \leftarrow digs$ \\ -\\ -Eliminate the lower $k$ digits. \\ -5. For $ix$ from $0$ to $k - 1$ do \\ -\hspace{3mm}5.1 $\mu \leftarrow x_{ix} \cdot \rho \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{3mm}5.2 $u \leftarrow 0$ \\ -\hspace{3mm}5.3 For $iy$ from $0$ to $k - 1$ do \\ -\hspace{6mm}5.3.1 $\hat r \leftarrow \mu n_{iy} + x_{ix + iy} + u$ \\ -\hspace{6mm}5.3.2 $x_{ix + iy} \leftarrow \hat r \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{6mm}5.3.3 $u \leftarrow \lfloor \hat r / \beta \rfloor$ \\ -\hspace{3mm}5.4 While $u > 0$ do \\ -\hspace{6mm}5.4.1 $iy \leftarrow iy + 1$ \\ -\hspace{6mm}5.4.2 $x_{ix + iy} \leftarrow x_{ix + iy} + u$ \\ -\hspace{6mm}5.4.3 $u \leftarrow \lfloor x_{ix+iy} / \beta \rfloor$ \\ -\hspace{6mm}5.4.4 $x_{ix + iy} \leftarrow x_{ix+iy} \mbox{ (mod }\beta\mbox{)}$ \\ -\\ -Divide by $\beta^k$ and fix up as required. \\ -6. $x \leftarrow \lfloor x / \beta^k \rfloor$ \\ -7. If $x \ge n$ then \\ -\hspace{3mm}7.1 $x \leftarrow x - n$ \\ -8. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_montgomery\_reduce} -\end{figure} - -\textbf{Algorithm mp\_montgomery\_reduce.} -This algorithm reduces the input $x$ modulo $n$ in place using the Montgomery reduction algorithm. The algorithm is loosely based -on algorithm 14.32 of \cite[pp.601]{HAC} except it merges the multiplication of $\mu n \beta^t$ with the addition in the inner loop. The -restrictions on this algorithm are fairly easy to adapt to. First $0 \le x < n^2$ bounds the input to numbers in the same range as -for the Barrett algorithm. Additionally $n > 1$ will ensure a modular inverse $\rho$ exists. $\rho$ must be calculated in -advance of this algorithm. Finally the variable $k$ is fixed and a pseudonym for $n.used$. - -Step 2 decides whether a faster Montgomery algorithm can be used. It is based on the Comba technique meaning that there are limits on -the size of the input. This algorithm is discussed in ~COMBARED~. - -Step 5 is the main reduction loop of the algorithm. The value of $\mu$ is calculated once per iteration in the outer loop. The inner loop -calculates $x + \mu n \beta^{ix}$ by multiplying $\mu n$ and adding the result to $x$ shifted by $ix$ digits. Both the addition and -multiplication are performed in the same loop to save time and memory. Step 5.4 will handle any additional carries that escape the inner loop. - -Using a quick inspection this algorithm requires $n$ single precision multiplications for the outer loop and $n^2$ single precision multiplications -in the inner loop. In total $n^2 + n$ single precision multiplications which compares favourably to Barrett at $n^2 + 2n - 1$ single precision -multiplications. - -EXAM,bn_mp_montgomery_reduce.c - -This is the baseline implementation of the Montgomery reduction algorithm. Lines @30,digs@ to @35,}@ determine if the Comba based -routine can be used instead. Line @47,mu@ computes the value of $\mu$ for that particular iteration of the outer loop. - -The multiplication $\mu n \beta^{ix}$ is performed in one step in the inner loop. The alias $tmpx$ refers to the $ix$'th digit of $x$ and -the alias $tmpn$ refers to the modulus $n$. - -\subsection{Faster ``Comba'' Montgomery Reduction} -MARK,COMBARED - -The Montgomery reduction requires fewer single precision multiplications than a Barrett reduction, however it is much slower due to the serial -nature of the inner loop. The Barrett reduction algorithm requires two slightly modified multipliers which can be implemented with the Comba -technique. The Montgomery reduction algorithm cannot directly use the Comba technique to any significant advantage since the inner loop calculates -a $k \times 1$ product $k$ times. - -The biggest obstacle is that at the $ix$'th iteration of the outer loop the value of $x_{ix}$ is required to calculate $\mu$. This means the -carries from $0$ to $ix - 1$ must have been propagated upwards to form a valid $ix$'th digit. The solution as it turns out is very simple. -Perform a Comba like multiplier and inside the outer loop just after the inner loop fix up the $ix + 1$'th digit by forwarding the carry. - -With this change in place the Montgomery reduction algorithm can be performed with a Comba style multiplication loop which substantially increases -the speed of the algorithm. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{fast\_mp\_montgomery\_reduce}. \\ -\textbf{Input}. mp\_int $x$, mp\_int $n$ and a digit $\rho \equiv -1/n_0 \mbox{ (mod }n\mbox{)}$. \\ -\hspace{11.5mm}($0 \le x < n^2, n > 1, (n, \beta) = 1, \beta^k > n$) \\ -\textbf{Output}. $\beta^{-k}x \mbox{ (mod }n\mbox{)}$ \\ -\hline \\ -Place an array of \textbf{MP\_WARRAY} mp\_word variables called $\hat W$ on the stack. \\ -1. if $x.alloc < n.used + 1$ then grow $x$ to $n.used + 1$ digits. \\ -Copy the digits of $x$ into the array $\hat W$ \\ -2. For $ix$ from $0$ to $x.used - 1$ do \\ -\hspace{3mm}2.1 $\hat W_{ix} \leftarrow x_{ix}$ \\ -3. For $ix$ from $x.used$ to $2n.used - 1$ do \\ -\hspace{3mm}3.1 $\hat W_{ix} \leftarrow 0$ \\ -Elimiate the lower $k$ digits. \\ -4. for $ix$ from $0$ to $n.used - 1$ do \\ -\hspace{3mm}4.1 $\mu \leftarrow \hat W_{ix} \cdot \rho \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{3mm}4.2 For $iy$ from $0$ to $n.used - 1$ do \\ -\hspace{6mm}4.2.1 $\hat W_{iy + ix} \leftarrow \hat W_{iy + ix} + \mu \cdot n_{iy}$ \\ -\hspace{3mm}4.3 $\hat W_{ix + 1} \leftarrow \hat W_{ix + 1} + \lfloor \hat W_{ix} / \beta \rfloor$ \\ -Propagate carries upwards. \\ -5. for $ix$ from $n.used$ to $2n.used + 1$ do \\ -\hspace{3mm}5.1 $\hat W_{ix + 1} \leftarrow \hat W_{ix + 1} + \lfloor \hat W_{ix} / \beta \rfloor$ \\ -Shift right and reduce modulo $\beta$ simultaneously. \\ -6. for $ix$ from $0$ to $n.used + 1$ do \\ -\hspace{3mm}6.1 $x_{ix} \leftarrow \hat W_{ix + n.used} \mbox{ (mod }\beta\mbox{)}$ \\ -Zero excess digits and fixup $x$. \\ -7. if $x.used > n.used + 1$ then do \\ -\hspace{3mm}7.1 for $ix$ from $n.used + 1$ to $x.used - 1$ do \\ -\hspace{6mm}7.1.1 $x_{ix} \leftarrow 0$ \\ -8. $x.used \leftarrow n.used + 1$ \\ -9. Clamp excessive digits of $x$. \\ -10. If $x \ge n$ then \\ -\hspace{3mm}10.1 $x \leftarrow x - n$ \\ -11. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm fast\_mp\_montgomery\_reduce} -\end{figure} - -\textbf{Algorithm fast\_mp\_montgomery\_reduce.} -This algorithm will compute the Montgomery reduction of $x$ modulo $n$ using the Comba technique. It is on most computer platforms significantly -faster than algorithm mp\_montgomery\_reduce and algorithm mp\_reduce (\textit{Barrett reduction}). The algorithm has the same restrictions -on the input as the baseline reduction algorithm. An additional two restrictions are imposed on this algorithm. The number of digits $k$ in the -the modulus $n$ must not violate $MP\_WARRAY > 2k +1$ and $n < \delta$. When $\beta = 2^{28}$ this algorithm can be used to reduce modulo -a modulus of at most $3,556$ bits in length. - -As in the other Comba reduction algorithms there is a $\hat W$ array which stores the columns of the product. It is initially filled with the -contents of $x$ with the excess digits zeroed. The reduction loop is very similar the to the baseline loop at heart. The multiplication on step -4.1 can be single precision only since $ab \mbox{ (mod }\beta\mbox{)} \equiv (a \mbox{ mod }\beta)(b \mbox{ mod }\beta)$. Some multipliers such -as those on the ARM processors take a variable length time to complete depending on the number of bytes of result it must produce. By performing -a single precision multiplication instead half the amount of time is spent. - -Also note that digit $\hat W_{ix}$ must have the carry from the $ix - 1$'th digit propagated upwards in order for this to work. That is what step -4.3 will do. In effect over the $n.used$ iterations of the outer loop the $n.used$'th lower columns all have the their carries propagated forwards. Note -how the upper bits of those same words are not reduced modulo $\beta$. This is because those values will be discarded shortly and there is no -point. - -Step 5 will propgate the remainder of the carries upwards. On step 6 the columns are reduced modulo $\beta$ and shifted simultaneously as they are -stored in the destination $x$. - -EXAM,bn_fast_mp_montgomery_reduce.c - -The $\hat W$ array is first filled with digits of $x$ on line @49,for@ then the rest of the digits are zeroed on line @54,for@. Both loops share -the same alias variables to make the code easier to read. - -The value of $\mu$ is calculated in an interesting fashion. First the value $\hat W_{ix}$ is reduced modulo $\beta$ and cast to a mp\_digit. This -forces the compiler to use a single precision multiplication and prevents any concerns about loss of precision. Line @101,>>@ fixes the carry -for the next iteration of the loop by propagating the carry from $\hat W_{ix}$ to $\hat W_{ix+1}$. - -The for loop on line @113,for@ propagates the rest of the carries upwards through the columns. The for loop on line @126,for@ reduces the columns -modulo $\beta$ and shifts them $k$ places at the same time. The alias $\_ \hat W$ actually refers to the array $\hat W$ starting at the $n.used$'th -digit, that is $\_ \hat W_{t} = \hat W_{n.used + t}$. - -\subsection{Montgomery Setup} -To calculate the variable $\rho$ a relatively simple algorithm will be required. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_montgomery\_setup}. \\ -\textbf{Input}. mp\_int $n$ ($n > 1$ and $(n, 2) = 1$) \\ -\textbf{Output}. $\rho \equiv -1/n_0 \mbox{ (mod }\beta\mbox{)}$ \\ -\hline \\ -1. $b \leftarrow n_0$ \\ -2. If $b$ is even return(\textit{MP\_VAL}) \\ -3. $x \leftarrow ((b + 2) \mbox{ AND } 4) << 1) + b$ \\ -4. for $k$ from 0 to $3$ do \\ -\hspace{3mm}4.1 $x \leftarrow x \cdot (2 - bx)$ \\ -5. $\rho \leftarrow \beta - x \mbox{ (mod }\beta\mbox{)}$ \\ -6. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_montgomery\_setup} -\end{figure} - -\textbf{Algorithm mp\_montgomery\_setup.} -This algorithm will calculate the value of $\rho$ required within the Montgomery reduction algorithms. It uses a very interesting trick -to calculate $1/n_0$ when $\beta$ is a power of two. - -EXAM,bn_mp_montgomery_setup.c - -This source code computes the value of $\rho$ required to perform Montgomery reduction. It has been modified to avoid performing excess -multiplications when $\beta$ is not the default 28-bits. - -\section{The Diminished Radix Algorithm} -The Diminished Radix method of modular reduction \cite{DRMET} is a fairly clever technique which can be more efficient than either the Barrett -or Montgomery methods for certain forms of moduli. The technique is based on the following simple congruence. - -\begin{equation} -(x \mbox{ mod } n) + k \lfloor x / n \rfloor \equiv x \mbox{ (mod }(n - k)\mbox{)} -\end{equation} - -This observation was used in the MMB \cite{MMB} block cipher to create a diffusion primitive. It used the fact that if $n = 2^{31}$ and $k=1$ that -then a x86 multiplier could produce the 62-bit product and use the ``shrd'' instruction to perform a double-precision right shift. The proof -of the above equation is very simple. First write $x$ in the product form. - -\begin{equation} -x = qn + r -\end{equation} - -Now reduce both sides modulo $(n - k)$. - -\begin{equation} -x \equiv qk + r \mbox{ (mod }(n-k)\mbox{)} -\end{equation} - -The variable $n$ reduces modulo $n - k$ to $k$. By putting $q = \lfloor x/n \rfloor$ and $r = x \mbox{ mod } n$ -into the equation the original congruence is reproduced, thus concluding the proof. The following algorithm is based on this observation. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{Diminished Radix Reduction}. \\ -\textbf{Input}. Integer $x$, $n$, $k$ \\ -\textbf{Output}. $x \mbox{ mod } (n - k)$ \\ -\hline \\ -1. $q \leftarrow \lfloor x / n \rfloor$ \\ -2. $q \leftarrow k \cdot q$ \\ -3. $x \leftarrow x \mbox{ (mod }n\mbox{)}$ \\ -4. $x \leftarrow x + q$ \\ -5. If $x \ge (n - k)$ then \\ -\hspace{3mm}5.1 $x \leftarrow x - (n - k)$ \\ -\hspace{3mm}5.2 Goto step 1. \\ -6. Return $x$ \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm Diminished Radix Reduction} -\label{fig:DR} -\end{figure} - -This algorithm will reduce $x$ modulo $n - k$ and return the residue. If $0 \le x < (n - k)^2$ then the algorithm will loop almost always -once or twice and occasionally three times. For simplicity sake the value of $x$ is bounded by the following simple polynomial. - -\begin{equation} -0 \le x < n^2 + k^2 - 2nk -\end{equation} - -The true bound is $0 \le x < (n - k - 1)^2$ but this has quite a few more terms. The value of $q$ after step 1 is bounded by the following. - -\begin{equation} -q < n - 2k - k^2/n -\end{equation} - -Since $k^2$ is going to be considerably smaller than $n$ that term will always be zero. The value of $x$ after step 3 is bounded trivially as -$0 \le x < n$. By step four the sum $x + q$ is bounded by - -\begin{equation} -0 \le q + x < (k + 1)n - 2k^2 - 1 -\end{equation} - -With a second pass $q$ will be loosely bounded by $0 \le q < k^2$ after step 2 while $x$ will still be loosely bounded by $0 \le x < n$ after step 3. After the second pass it is highly unlike that the -sum in step 4 will exceed $n - k$. In practice fewer than three passes of the algorithm are required to reduce virtually every input in the -range $0 \le x < (n - k - 1)^2$. - -\begin{figure} -\begin{small} -\begin{center} -\begin{tabular}{|l|} -\hline -$x = 123456789, n = 256, k = 3$ \\ -\hline $q \leftarrow \lfloor x/n \rfloor = 482253$ \\ -$q \leftarrow q*k = 1446759$ \\ -$x \leftarrow x \mbox{ mod } n = 21$ \\ -$x \leftarrow x + q = 1446780$ \\ -$x \leftarrow x - (n - k) = 1446527$ \\ -\hline -$q \leftarrow \lfloor x/n \rfloor = 5650$ \\ -$q \leftarrow q*k = 16950$ \\ -$x \leftarrow x \mbox{ mod } n = 127$ \\ -$x \leftarrow x + q = 17077$ \\ -$x \leftarrow x - (n - k) = 16824$ \\ -\hline -$q \leftarrow \lfloor x/n \rfloor = 65$ \\ -$q \leftarrow q*k = 195$ \\ -$x \leftarrow x \mbox{ mod } n = 184$ \\ -$x \leftarrow x + q = 379$ \\ -$x \leftarrow x - (n - k) = 126$ \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Example Diminished Radix Reduction} -\label{fig:EXDR} -\end{figure} - -Figure~\ref{fig:EXDR} demonstrates the reduction of $x = 123456789$ modulo $n - k = 253$ when $n = 256$ and $k = 3$. Note that even while $x$ -is considerably larger than $(n - k - 1)^2 = 63504$ the algorithm still converges on the modular residue exceedingly fast. In this case only -three passes were required to find the residue $x \equiv 126$. - - -\subsection{Choice of Moduli} -On the surface this algorithm looks like a very expensive algorithm. It requires a couple of subtractions followed by multiplication and other -modular reductions. The usefulness of this algorithm becomes exceedingly clear when an appropriate moduli is chosen. - -Division in general is a very expensive operation to perform. The one exception is when the division is by a power of the radix of representation used. -Division by ten for example is simple for pencil and paper mathematics since it amounts to shifting the decimal place to the right. Similarly division -by two (\textit{or powers of two}) is very simple for binary computers to perform. It would therefore seem logical to choose $n$ of the form $2^p$ -which would imply that $\lfloor x / n \rfloor$ is a simple shift of $x$ right $p$ bits. - -However, there is one operation related to division of power of twos that is even faster than this. If $n = \beta^p$ then the division may be -performed by moving whole digits to the right $p$ places. In practice division by $\beta^p$ is much faster than division by $2^p$ for any $p$. -Also with the choice of $n = \beta^p$ reducing $x$ modulo $n$ requires zeroing the digits above the $p-1$'th digit of $x$. - -Throughout the next section the term ``restricted modulus'' will refer to a modulus of the form $\beta^p - k$ where as the term ``unrestricted -modulus'' will refer to a modulus of the form $2^p - k$. The word ``restricted'' in this case refers to the fact that it is based on the -$2^p$ logic except $p$ must be a multiple of $lg(\beta)$. - -\subsection{Choice of $k$} -Now that division and reduction (\textit{step 1 and 3 of figure~\ref{fig:DR}}) have been optimized to simple digit operations the multiplication by $k$ -in step 2 is the most expensive operation. Fortunately the choice of $k$ is not terribly limited. For all intents and purposes it might -as well be a single digit. The smaller the value of $k$ is the faster the algorithm will be. - -\subsection{Restricted Diminished Radix Reduction} -The restricted Diminished Radix algorithm can quickly reduce an input modulo a modulus of the form $n = \beta^p - k$. This algorithm can reduce -an input $x$ within the range $0 \le x < n^2$ using only a couple passes of the algorithm demonstrated in figure~\ref{fig:DR}. The implementation -of this algorithm has been optimized to avoid additional overhead associated with a division by $\beta^p$, the multiplication by $k$ or the addition -of $x$ and $q$. The resulting algorithm is very efficient and can lead to substantial improvements over Barrett and Montgomery reduction when modular -exponentiations are performed. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_dr\_reduce}. \\ -\textbf{Input}. mp\_int $x$, $n$ and a mp\_digit $k = \beta - n_0$ \\ -\hspace{11.5mm}($0 \le x < n^2$, $n > 1$, $0 < k < \beta$) \\ -\textbf{Output}. $x \mbox{ mod } n$ \\ -\hline \\ -1. $m \leftarrow n.used$ \\ -2. If $x.alloc < 2m$ then grow $x$ to $2m$ digits. \\ -3. $\mu \leftarrow 0$ \\ -4. for $i$ from $0$ to $m - 1$ do \\ -\hspace{3mm}4.1 $\hat r \leftarrow k \cdot x_{m+i} + x_{i} + \mu$ \\ -\hspace{3mm}4.2 $x_{i} \leftarrow \hat r \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{3mm}4.3 $\mu \leftarrow \lfloor \hat r / \beta \rfloor$ \\ -5. $x_{m} \leftarrow \mu$ \\ -6. for $i$ from $m + 1$ to $x.used - 1$ do \\ -\hspace{3mm}6.1 $x_{i} \leftarrow 0$ \\ -7. Clamp excess digits of $x$. \\ -8. If $x \ge n$ then \\ -\hspace{3mm}8.1 $x \leftarrow x - n$ \\ -\hspace{3mm}8.2 Goto step 3. \\ -9. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_dr\_reduce} -\end{figure} - -\textbf{Algorithm mp\_dr\_reduce.} -This algorithm will perform the Dimished Radix reduction of $x$ modulo $n$. It has similar restrictions to that of the Barrett reduction -with the addition that $n$ must be of the form $n = \beta^m - k$ where $0 < k <\beta$. - -This algorithm essentially implements the pseudo-code in figure~\ref{fig:DR} except with a slight optimization. The division by $\beta^m$, multiplication by $k$ -and addition of $x \mbox{ mod }\beta^m$ are all performed simultaneously inside the loop on step 4. The division by $\beta^m$ is emulated by accessing -the term at the $m+i$'th position which is subsequently multiplied by $k$ and added to the term at the $i$'th position. After the loop the $m$'th -digit is set to the carry and the upper digits are zeroed. Steps 5 and 6 emulate the reduction modulo $\beta^m$ that should have happend to -$x$ before the addition of the multiple of the upper half. - -At step 8 if $x$ is still larger than $n$ another pass of the algorithm is required. First $n$ is subtracted from $x$ and then the algorithm resumes -at step 3. - -EXAM,bn_mp_dr_reduce.c - -The first step is to grow $x$ as required to $2m$ digits since the reduction is performed in place on $x$. The label on line @49,top:@ is where -the algorithm will resume if further reduction passes are required. In theory it could be placed at the top of the function however, the size of -the modulus and question of whether $x$ is large enough are invariant after the first pass meaning that it would be a waste of time. - -The aliases $tmpx1$ and $tmpx2$ refer to the digits of $x$ where the latter is offset by $m$ digits. By reading digits from $x$ offset by $m$ digits -a division by $\beta^m$ can be simulated virtually for free. The loop on line @61,for@ performs the bulk of the work (\textit{corresponds to step 4 of algorithm 7.11}) -in this algorithm. - -By line @68,mu@ the pointer $tmpx1$ points to the $m$'th digit of $x$ which is where the final carry will be placed. Similarly by line @71,for@ the -same pointer will point to the $m+1$'th digit where the zeroes will be placed. - -Since the algorithm is only valid if both $x$ and $n$ are greater than zero an unsigned comparison suffices to determine if another pass is required. -With the same logic at line @82,sub@ the value of $x$ is known to be greater than or equal to $n$ meaning that an unsigned subtraction can be used -as well. Since the destination of the subtraction is the larger of the inputs the call to algorithm s\_mp\_sub cannot fail and the return code -does not need to be checked. - -\subsubsection{Setup} -To setup the restricted Diminished Radix algorithm the value $k = \beta - n_0$ is required. This algorithm is not really complicated but provided for -completeness. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_dr\_setup}. \\ -\textbf{Input}. mp\_int $n$ \\ -\textbf{Output}. $k = \beta - n_0$ \\ -\hline \\ -1. $k \leftarrow \beta - n_0$ \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_dr\_setup} -\end{figure} - -EXAM,bn_mp_dr_setup.c - -\subsubsection{Modulus Detection} -Another algorithm which will be useful is the ability to detect a restricted Diminished Radix modulus. An integer is said to be -of restricted Diminished Radix form if all of the digits are equal to $\beta - 1$ except the trailing digit which may be any value. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_dr\_is\_modulus}. \\ -\textbf{Input}. mp\_int $n$ \\ -\textbf{Output}. $1$ if $n$ is in D.R form, $0$ otherwise \\ -\hline -1. If $n.used < 2$ then return($0$). \\ -2. for $ix$ from $1$ to $n.used - 1$ do \\ -\hspace{3mm}2.1 If $n_{ix} \ne \beta - 1$ return($0$). \\ -3. Return($1$). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_dr\_is\_modulus} -\end{figure} - -\textbf{Algorithm mp\_dr\_is\_modulus.} -This algorithm determines if a value is in Diminished Radix form. Step 1 rejects obvious cases where fewer than two digits are -in the mp\_int. Step 2 tests all but the first digit to see if they are equal to $\beta - 1$. If the algorithm manages to get to -step 3 then $n$ must of Diminished Radix form. - -EXAM,bn_mp_dr_is_modulus.c - -\subsection{Unrestricted Diminished Radix Reduction} -The unrestricted Diminished Radix algorithm allows modular reductions to be performed when the modulus is of the form $2^p - k$. This algorithm -is a straightforward adaptation of algorithm~\ref{fig:DR}. - -In general the restricted Diminished Radix reduction algorithm is much faster since it has considerably lower overhead. However, this new -algorithm is much faster than either Montgomery or Barrett reduction when the moduli are of the appropriate form. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_reduce\_2k}. \\ -\textbf{Input}. mp\_int $a$ and $n$. mp\_digit $k$ \\ -\hspace{11.5mm}($a \ge 0$, $n > 1$, $0 < k < \beta$, $n + k$ is a power of two) \\ -\textbf{Output}. $a \mbox{ (mod }n\mbox{)}$ \\ -\hline -1. $p \leftarrow \lceil lg(n) \rceil$ (\textit{mp\_count\_bits}) \\ -2. While $a \ge n$ do \\ -\hspace{3mm}2.1 $q \leftarrow \lfloor a / 2^p \rfloor$ (\textit{mp\_div\_2d}) \\ -\hspace{3mm}2.2 $a \leftarrow a \mbox{ (mod }2^p\mbox{)}$ (\textit{mp\_mod\_2d}) \\ -\hspace{3mm}2.3 $q \leftarrow q \cdot k$ (\textit{mp\_mul\_d}) \\ -\hspace{3mm}2.4 $a \leftarrow a - q$ (\textit{s\_mp\_sub}) \\ -\hspace{3mm}2.5 If $a \ge n$ then do \\ -\hspace{6mm}2.5.1 $a \leftarrow a - n$ \\ -3. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_reduce\_2k} -\end{figure} - -\textbf{Algorithm mp\_reduce\_2k.} -This algorithm quickly reduces an input $a$ modulo an unrestricted Diminished Radix modulus $n$. Division by $2^p$ is emulated with a right -shift which makes the algorithm fairly inexpensive to use. - -EXAM,bn_mp_reduce_2k.c - -The algorithm mp\_count\_bits calculates the number of bits in an mp\_int which is used to find the initial value of $p$. The call to mp\_div\_2d -on line @31,mp_div_2d@ calculates both the quotient $q$ and the remainder $a$ required. By doing both in a single function call the code size -is kept fairly small. The multiplication by $k$ is only performed if $k > 1$. This allows reductions modulo $2^p - 1$ to be performed without -any multiplications. - -The unsigned s\_mp\_add, mp\_cmp\_mag and s\_mp\_sub are used in place of their full sign counterparts since the inputs are only valid if they are -positive. By using the unsigned versions the overhead is kept to a minimum. - -\subsubsection{Unrestricted Setup} -To setup this reduction algorithm the value of $k = 2^p - n$ is required. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_reduce\_2k\_setup}. \\ -\textbf{Input}. mp\_int $n$ \\ -\textbf{Output}. $k = 2^p - n$ \\ -\hline -1. $p \leftarrow \lceil lg(n) \rceil$ (\textit{mp\_count\_bits}) \\ -2. $x \leftarrow 2^p$ (\textit{mp\_2expt}) \\ -3. $x \leftarrow x - n$ (\textit{mp\_sub}) \\ -4. $k \leftarrow x_0$ \\ -5. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_reduce\_2k\_setup} -\end{figure} - -\textbf{Algorithm mp\_reduce\_2k\_setup.} -This algorithm computes the value of $k$ required for the algorithm mp\_reduce\_2k. By making a temporary variable $x$ equal to $2^p$ a subtraction -is sufficient to solve for $k$. Alternatively if $n$ has more than one digit the value of $k$ is simply $\beta - n_0$. - -EXAM,bn_mp_reduce_2k_setup.c - -\subsubsection{Unrestricted Detection} -An integer $n$ is a valid unrestricted Diminished Radix modulus if either of the following are true. - -\begin{enumerate} -\item The number has only one digit. -\item The number has more than one digit and every bit from the $\beta$'th to the most significant is one. -\end{enumerate} - -If either condition is true than there is a power of two namely $2^p$ such that $0 < 2^p - n < \beta$. If the input is only -one digit than it will always be of the correct form. Otherwise all of the bits above the first digit must be one. This arises from the fact -that there will be value of $k$ that when added to the modulus causes a carry in the first digit which propagates all the way to the most -significant bit. The resulting sum will be a power of two. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_reduce\_is\_2k}. \\ -\textbf{Input}. mp\_int $n$ \\ -\textbf{Output}. $1$ if of proper form, $0$ otherwise \\ -\hline -1. If $n.used = 0$ then return($0$). \\ -2. If $n.used = 1$ then return($1$). \\ -3. $p \leftarrow \rceil lg(n) \lceil$ (\textit{mp\_count\_bits}) \\ -4. for $x$ from $lg(\beta)$ to $p$ do \\ -\hspace{3mm}4.1 If the ($x \mbox{ mod }lg(\beta)$)'th bit of the $\lfloor x / lg(\beta) \rfloor$ of $n$ is zero then return($0$). \\ -5. Return($1$). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_reduce\_is\_2k} -\end{figure} - -\textbf{Algorithm mp\_reduce\_is\_2k.} -This algorithm quickly determines if a modulus is of the form required for algorithm mp\_reduce\_2k to function properly. - -EXAM,bn_mp_reduce_is_2k.c - - - -\section{Algorithm Comparison} -So far three very different algorithms for modular reduction have been discussed. Each of the algorithms have their own strengths and weaknesses -that makes having such a selection very useful. The following table sumarizes the three algorithms along with comparisons of work factors. Since -all three algorithms have the restriction that $0 \le x < n^2$ and $n > 1$ those limitations are not included in the table. - -\begin{center} -\begin{small} -\begin{tabular}{|c|c|c|c|c|c|} -\hline \textbf{Method} & \textbf{Work Required} & \textbf{Limitations} & \textbf{$m = 8$} & \textbf{$m = 32$} & \textbf{$m = 64$} \\ -\hline Barrett & $m^2 + 2m - 1$ & None & $79$ & $1087$ & $4223$ \\ -\hline Montgomery & $m^2 + m$ & $n$ must be odd & $72$ & $1056$ & $4160$ \\ -\hline D.R. & $2m$ & $n = \beta^m - k$ & $16$ & $64$ & $128$ \\ -\hline -\end{tabular} -\end{small} -\end{center} - -In theory Montgomery and Barrett reductions would require roughly the same amount of time to complete. However, in practice since Montgomery -reduction can be written as a single function with the Comba technique it is much faster. Barrett reduction suffers from the overhead of -calling the half precision multipliers, addition and division by $\beta$ algorithms. - -For almost every cryptographic algorithm Montgomery reduction is the algorithm of choice. The one set of algorithms where Diminished Radix reduction truly -shines are based on the discrete logarithm problem such as Diffie-Hellman \cite{DH} and ElGamal \cite{ELGAMAL}. In these algorithms -primes of the form $\beta^m - k$ can be found and shared amongst users. These primes will allow the Diminished Radix algorithm to be used in -modular exponentiation to greatly speed up the operation. - - - -\section*{Exercises} -\begin{tabular}{cl} -$\left [ 3 \right ]$ & Prove that the ``trick'' in algorithm mp\_montgomery\_setup actually \\ - & calculates the correct value of $\rho$. \\ - & \\ -$\left [ 2 \right ]$ & Devise an algorithm to reduce modulo $n + k$ for small $k$ quickly. \\ - & \\ -$\left [ 4 \right ]$ & Prove that the pseudo-code algorithm ``Diminished Radix Reduction'' \\ - & (\textit{figure~\ref{fig:DR}}) terminates. Also prove the probability that it will \\ - & terminate within $1 \le k \le 10$ iterations. \\ - & \\ -\end{tabular} - - -\chapter{Exponentiation} -Exponentiation is the operation of raising one variable to the power of another, for example, $a^b$. A variant of exponentiation, computed -in a finite field or ring, is called modular exponentiation. This latter style of operation is typically used in public key -cryptosystems such as RSA and Diffie-Hellman. The ability to quickly compute modular exponentiations is of great benefit to any -such cryptosystem and many methods have been sought to speed it up. - -\section{Exponentiation Basics} -A trivial algorithm would simply multiply $a$ against itself $b - 1$ times to compute the exponentiation desired. However, as $b$ grows in size -the number of multiplications becomes prohibitive. Imagine what would happen if $b$ $\approx$ $2^{1024}$ as is the case when computing an RSA signature -with a $1024$-bit key. Such a calculation could never be completed as it would take simply far too long. - -Fortunately there is a very simple algorithm based on the laws of exponents. Recall that $lg_a(a^b) = b$ and that $lg_a(a^ba^c) = b + c$ which -are two trivial relationships between the base and the exponent. Let $b_i$ represent the $i$'th bit of $b$ starting from the least -significant bit. If $b$ is a $k$-bit integer than the following equation is true. - -\begin{equation} -a^b = \prod_{i=0}^{k-1} a^{2^i \cdot b_i} -\end{equation} - -By taking the base $a$ logarithm of both sides of the equation the following equation is the result. - -\begin{equation} -b = \sum_{i=0}^{k-1}2^i \cdot b_i -\end{equation} - -The term $a^{2^i}$ can be found from the $i - 1$'th term by squaring the term since $\left ( a^{2^i} \right )^2$ is equal to -$a^{2^{i+1}}$. This observation forms the basis of essentially all fast exponentiation algorithms. It requires $k$ squarings and on average -$k \over 2$ multiplications to compute the result. This is indeed quite an improvement over simply multiplying by $a$ a total of $b-1$ times. - -While this current method is a considerable speed up there are further improvements to be made. For example, the $a^{2^i}$ term does not need to -be computed in an auxilary variable. Consider the following equivalent algorithm. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{Left to Right Exponentiation}. \\ -\textbf{Input}. Integer $a$, $b$ and $k$ \\ -\textbf{Output}. $c = a^b$ \\ -\hline \\ -1. $c \leftarrow 1$ \\ -2. for $i$ from $k - 1$ to $0$ do \\ -\hspace{3mm}2.1 $c \leftarrow c^2$ \\ -\hspace{3mm}2.2 $c \leftarrow c \cdot a^{b_i}$ \\ -3. Return $c$. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Left to Right Exponentiation} -\label{fig:LTOR} -\end{figure} - -This algorithm starts from the most significant bit and works towards the least significant bit. When the $i$'th bit of $b$ is set $a$ is -multiplied against the current product. In each iteration the product is squared which doubles the exponent of the individual terms of the -product. - -For example, let $b = 101100_2 \equiv 44_{10}$. The following chart demonstrates the actions of the algorithm. - -\newpage\begin{figure} -\begin{center} -\begin{tabular}{|c|c|} -\hline \textbf{Value of $i$} & \textbf{Value of $c$} \\ -\hline - & $1$ \\ -\hline $5$ & $a$ \\ -\hline $4$ & $a^2$ \\ -\hline $3$ & $a^4 \cdot a$ \\ -\hline $2$ & $a^8 \cdot a^2 \cdot a$ \\ -\hline $1$ & $a^{16} \cdot a^4 \cdot a^2$ \\ -\hline $0$ & $a^{32} \cdot a^8 \cdot a^4$ \\ -\hline -\end{tabular} -\end{center} -\caption{Example of Left to Right Exponentiation} -\end{figure} - -When the product $a^{32} \cdot a^8 \cdot a^4$ is simplified it is equal $a^{44}$ which is the desired exponentiation. This particular algorithm is -called ``Left to Right'' because it reads the exponent in that order. All of the exponentiation algorithms that will be presented are of this nature. - -\subsection{Single Digit Exponentiation} -The first algorithm in the series of exponentiation algorithms will be an unbounded algorithm where the exponent is a single digit. It is intended -to be used when a small power of an input is required (\textit{e.g. $a^5$}). It is faster than simply multiplying $b - 1$ times for all values of -$b$ that are greater than three. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_expt\_d}. \\ -\textbf{Input}. mp\_int $a$ and mp\_digit $b$ \\ -\textbf{Output}. $c = a^b$ \\ -\hline \\ -1. $g \leftarrow a$ (\textit{mp\_init\_copy}) \\ -2. $c \leftarrow 1$ (\textit{mp\_set}) \\ -3. for $x$ from 1 to $lg(\beta)$ do \\ -\hspace{3mm}3.1 $c \leftarrow c^2$ (\textit{mp\_sqr}) \\ -\hspace{3mm}3.2 If $b$ AND $2^{lg(\beta) - 1} \ne 0$ then \\ -\hspace{6mm}3.2.1 $c \leftarrow c \cdot g$ (\textit{mp\_mul}) \\ -\hspace{3mm}3.3 $b \leftarrow b << 1$ \\ -4. Clear $g$. \\ -5. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_expt\_d} -\end{figure} - -\textbf{Algorithm mp\_expt\_d.} -This algorithm computes the value of $a$ raised to the power of a single digit $b$. It uses the left to right exponentiation algorithm to -quickly compute the exponentiation. It is loosely based on algorithm 14.79 of HAC \cite[pp. 615]{HAC} with the difference that the -exponent is a fixed width. - -A copy of $a$ is made first to allow destination variable $c$ be the same as the source variable $a$. The result is set to the initial value of -$1$ in the subsequent step. - -Inside the loop the exponent is read from the most significant bit first down to the least significant bit. First $c$ is invariably squared -on step 3.1. In the following step if the most significant bit of $b$ is one the copy of $a$ is multiplied against $c$. The value -of $b$ is shifted left one bit to make the next bit down from the most signficant bit the new most significant bit. In effect each -iteration of the loop moves the bits of the exponent $b$ upwards to the most significant location. - -EXAM,bn_mp_expt_d.c - --- Some note later. - -\section{$k$-ary Exponentiation} -When calculating an exponentiation the most time consuming bottleneck is the multiplications which are in general a small factor -slower than squaring. Recall from the previous algorithm that $b_{i}$ refers to the $i$'th bit of the exponent $b$. Suppose instead it referred to -the $i$'th $k$-bit digit of the exponent of $b$. For $k = 1$ the definitions are synonymous and for $k > 1$ algorithm~\ref{fig:KARY} -computes the same exponentiation. A group of $k$ bits from the exponent is called a \textit{window}. That is it is a small window on only a -portion of the entire exponent. Consider the following modification to the basic left to right exponentiation algorithm. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{$k$-ary Exponentiation}. \\ -\textbf{Input}. Integer $a$, $b$, $k$ and $t$ \\ -\textbf{Output}. $c = a^b$ \\ -\hline \\ -1. $c \leftarrow 1$ \\ -2. for $i$ from $t - 1$ to $0$ do \\ -\hspace{3mm}2.1 $c \leftarrow c^{2^k} $ \\ -\hspace{3mm}2.2 Extract the $i$'th $k$-bit word from $b$ and store it in $g$. \\ -\hspace{3mm}2.3 $c \leftarrow c \cdot a^g$ \\ -3. Return $c$. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{$k$-ary Exponentiation} -\label{fig:KARY} -\end{figure} - -The squaring on step 2.1 can be calculated by squaring the value $c$ successively $k$ times. If the values of $a^g$ for $0 < g < 2^k$ have been -precomputed this algorithm requires only $t$ multiplications and $tk$ squarings. The table can be generated with $2^{k - 1} - 1$ squarings and -$2^{k - 1} + 1$ multiplications. This algorithm assumes that the number of bits in the exponent is evenly divisible by $k$. -However, when it is not the remaining $0 < x \le k - 1$ bits can be handled with algorithm~\ref{fig:LTOR}. - -Suppose $k = 4$ and $t = 100$. This modified algorithm will require $109$ multiplications and $408$ squarings to compute the exponentiation. The -original algorithm would on average have required $200$ multiplications and $400$ squrings to compute the same value. The total number of squarings -has increased slightly but the number of multiplications has nearly halved. - -\subsection{Optimal Values of $k$} -An optimal value of $k$ will minimize $2^{k} + \lceil n / k \rceil + n - 1$ for a fixed number of bits in the exponent $n$. The simplest -approach is to brute force search amongst the values $k = 2, 3, \ldots, 8$ for the lowest result. Table~\ref{fig:OPTK} lists optimal values of $k$ -for various exponent sizes and compares the number of multiplication and squarings required against algorithm~\ref{fig:LTOR}. - -\begin{figure}[here] -\begin{center} -\begin{small} -\begin{tabular}{|c|c|c|c|c|c|} -\hline \textbf{Exponent (bits)} & \textbf{Optimal $k$} & \textbf{Work at $k$} & \textbf{Work with ~\ref{fig:LTOR}} \\ -\hline $16$ & $2$ & $27$ & $24$ \\ -\hline $32$ & $3$ & $49$ & $48$ \\ -\hline $64$ & $3$ & $92$ & $96$ \\ -\hline $128$ & $4$ & $175$ & $192$ \\ -\hline $256$ & $4$ & $335$ & $384$ \\ -\hline $512$ & $5$ & $645$ & $768$ \\ -\hline $1024$ & $6$ & $1257$ & $1536$ \\ -\hline $2048$ & $6$ & $2452$ & $3072$ \\ -\hline $4096$ & $7$ & $4808$ & $6144$ \\ -\hline -\end{tabular} -\end{small} -\end{center} -\caption{Optimal Values of $k$ for $k$-ary Exponentiation} -\label{fig:OPTK} -\end{figure} - -\subsection{Sliding-Window Exponentiation} -A simple modification to the previous algorithm is only generate the upper half of the table in the range $2^{k-1} \le g < 2^k$. Essentially -this is a table for all values of $g$ where the most significant bit of $g$ is a one. However, in order for this to be allowed in the -algorithm values of $g$ in the range $0 \le g < 2^{k-1}$ must be avoided. - -Table~\ref{fig:OPTK2} lists optimal values of $k$ for various exponent sizes and compares the work required against algorithm~\ref{fig:KARY}. - -\begin{figure}[here] -\begin{center} -\begin{small} -\begin{tabular}{|c|c|c|c|c|c|} -\hline \textbf{Exponent (bits)} & \textbf{Optimal $k$} & \textbf{Work at $k$} & \textbf{Work with ~\ref{fig:KARY}} \\ -\hline $16$ & $3$ & $24$ & $27$ \\ -\hline $32$ & $3$ & $45$ & $49$ \\ -\hline $64$ & $4$ & $87$ & $92$ \\ -\hline $128$ & $4$ & $167$ & $175$ \\ -\hline $256$ & $5$ & $322$ & $335$ \\ -\hline $512$ & $6$ & $628$ & $645$ \\ -\hline $1024$ & $6$ & $1225$ & $1257$ \\ -\hline $2048$ & $7$ & $2403$ & $2452$ \\ -\hline $4096$ & $8$ & $4735$ & $4808$ \\ -\hline -\end{tabular} -\end{small} -\end{center} -\caption{Optimal Values of $k$ for Sliding Window Exponentiation} -\label{fig:OPTK2} -\end{figure} - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{Sliding Window $k$-ary Exponentiation}. \\ -\textbf{Input}. Integer $a$, $b$, $k$ and $t$ \\ -\textbf{Output}. $c = a^b$ \\ -\hline \\ -1. $c \leftarrow 1$ \\ -2. for $i$ from $t - 1$ to $0$ do \\ -\hspace{3mm}2.1 If the $i$'th bit of $b$ is a zero then \\ -\hspace{6mm}2.1.1 $c \leftarrow c^2$ \\ -\hspace{3mm}2.2 else do \\ -\hspace{6mm}2.2.1 $c \leftarrow c^{2^k}$ \\ -\hspace{6mm}2.2.2 Extract the $k$ bits from $(b_{i}b_{i-1}\ldots b_{i-(k-1)})$ and store it in $g$. \\ -\hspace{6mm}2.2.3 $c \leftarrow c \cdot a^g$ \\ -\hspace{6mm}2.2.4 $i \leftarrow i - k$ \\ -3. Return $c$. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Sliding Window $k$-ary Exponentiation} -\end{figure} - -Similar to the previous algorithm this algorithm must have a special handler when fewer than $k$ bits are left in the exponent. While this -algorithm requires the same number of squarings it can potentially have fewer multiplications. The pre-computed table $a^g$ is also half -the size as the previous table. - -Consider the exponent $b = 111101011001000_2 \equiv 31432_{10}$ with $k = 3$ using both algorithms. The first algorithm will divide the exponent up as -the following five $3$-bit words $b \equiv \left ( 111, 101, 011, 001, 000 \right )_{2}$. The second algorithm will break the -exponent as $b \equiv \left ( 111, 101, 0, 110, 0, 100, 0 \right )_{2}$. The single digit $0$ in the second representation are where -a single squaring took place instead of a squaring and multiplication. In total the first method requires $10$ multiplications and $18$ -squarings. The second method requires $8$ multiplications and $18$ squarings. - -In general the sliding window method is never slower than the generic $k$-ary method and often it is slightly faster. - -\section{Modular Exponentiation} - -Modular exponentiation is essentially computing the power of a base within a finite field or ring. For example, computing -$d \equiv a^b \mbox{ (mod }c\mbox{)}$ is a modular exponentiation. Instead of first computing $a^b$ and then reducing it -modulo $c$ the intermediate result is reduced modulo $c$ after every squaring or multiplication operation. - -This guarantees that any intermediate result is bounded by $0 \le d \le c^2 - 2c + 1$ and can be reduced modulo $c$ quickly using -one of the algorithms presented in ~REDUCTION~. - -Before the actual modular exponentiation algorithm can be written a wrapper algorithm must be written first. This algorithm -will allow the exponent $b$ to be negative which is computed as $c \equiv \left (1 / a \right )^{\vert b \vert} \mbox{(mod }d\mbox{)}$. The -value of $(1/a) \mbox{ mod }c$ is computed using the modular inverse (\textit{see ~MODINV~}). If no inverse exists the algorithm -terminates with an error. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_exptmod}. \\ -\textbf{Input}. mp\_int $a$, $b$ and $c$ \\ -\textbf{Output}. $y \equiv g^x \mbox{ (mod }p\mbox{)}$ \\ -\hline \\ -1. If $c.sign = MP\_NEG$ return(\textit{MP\_VAL}). \\ -2. If $b.sign = MP\_NEG$ then \\ -\hspace{3mm}2.1 $g' \leftarrow g^{-1} \mbox{ (mod }c\mbox{)}$ \\ -\hspace{3mm}2.2 $x' \leftarrow \vert x \vert$ \\ -\hspace{3mm}2.3 Compute $d \equiv g'^{x'} \mbox{ (mod }c\mbox{)}$ via recursion. \\ -3. if $p$ is odd \textbf{OR} $p$ is a D.R. modulus then \\ -\hspace{3mm}3.1 Compute $y \equiv g^{x} \mbox{ (mod }p\mbox{)}$ via algorithm mp\_exptmod\_fast. \\ -4. else \\ -\hspace{3mm}4.1 Compute $y \equiv g^{x} \mbox{ (mod }p\mbox{)}$ via algorithm s\_mp\_exptmod. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_exptmod} -\end{figure} - -\textbf{Algorithm mp\_exptmod.} -The first algorithm which actually performs modular exponentiation is algorithm s\_mp\_exptmod. It is a sliding window $k$-ary algorithm -which uses Barrett reduction to reduce the product modulo $p$. The second algorithm mp\_exptmod\_fast performs the same operation -except it uses either Montgomery or Diminished Radix reduction. The two latter reduction algorithms are clumped in the same exponentiation -algorithm since their arguments are essentially the same (\textit{two mp\_ints and one mp\_digit}). - -EXAM,bn_mp_exptmod.c - -In order to keep the algorithms in a known state the first step on line @29,if@ is to reject any negative modulus as input. If the exponent is -negative the algorithm tries to perform a modular exponentiation with the modular inverse of the base $G$. The temporary variable $tmpG$ is assigned -the modular inverse of $G$ and $tmpX$ is assigned the absolute value of $X$. The algorithm will recuse with these new values with a positive -exponent. - -If the exponent is positive the algorithm resumes the exponentiation. Line @63,dr_@ determines if the modulus is of the restricted Diminished Radix -form. If it is not line @65,reduce@ attempts to determine if it is of a unrestricted Diminished Radix form. The integer $dr$ will take on one -of three values. - -\begin{enumerate} -\item $dr = 0$ means that the modulus is not of either restricted or unrestricted Diminished Radix form. -\item $dr = 1$ means that the modulus is of restricted Diminished Radix form. -\item $dr = 2$ means that the modulus is of unrestricted Diminished Radix form. -\end{enumerate} - -Line @69,if@ determines if the fast modular exponentiation algorithm can be used. It is allowed if $dr \ne 0$ or if the modulus is odd. Otherwise, -the slower s\_mp\_exptmod algorithm is used which uses Barrett reduction. - -\subsection{Barrett Modular Exponentiation} - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{s\_mp\_exptmod}. \\ -\textbf{Input}. mp\_int $a$, $b$ and $c$ \\ -\textbf{Output}. $y \equiv g^x \mbox{ (mod }p\mbox{)}$ \\ -\hline \\ -1. $k \leftarrow lg(x)$ \\ -2. $winsize \leftarrow \left \lbrace \begin{array}{ll} - 2 & \mbox{if }k \le 7 \\ - 3 & \mbox{if }7 < k \le 36 \\ - 4 & \mbox{if }36 < k \le 140 \\ - 5 & \mbox{if }140 < k \le 450 \\ - 6 & \mbox{if }450 < k \le 1303 \\ - 7 & \mbox{if }1303 < k \le 3529 \\ - 8 & \mbox{if }3529 < k \\ - \end{array} \right .$ \\ -3. Initialize $2^{winsize}$ mp\_ints in an array named $M$ and one mp\_int named $\mu$ \\ -4. Calculate the $\mu$ required for Barrett Reduction (\textit{mp\_reduce\_setup}). \\ -5. $M_1 \leftarrow g \mbox{ (mod }p\mbox{)}$ \\ -\\ -Setup the table of small powers of $g$. First find $g^{2^{winsize}}$ and then all multiples of it. \\ -6. $k \leftarrow 2^{winsize - 1}$ \\ -7. $M_{k} \leftarrow M_1$ \\ -8. for $ix$ from 0 to $winsize - 2$ do \\ -\hspace{3mm}8.1 $M_k \leftarrow \left ( M_k \right )^2$ (\textit{mp\_sqr}) \\ -\hspace{3mm}8.2 $M_k \leftarrow M_k \mbox{ (mod }p\mbox{)}$ (\textit{mp\_reduce}) \\ -9. for $ix$ from $2^{winsize - 1} + 1$ to $2^{winsize} - 1$ do \\ -\hspace{3mm}9.1 $M_{ix} \leftarrow M_{ix - 1} \cdot M_{1}$ (\textit{mp\_mul}) \\ -\hspace{3mm}9.2 $M_{ix} \leftarrow M_{ix} \mbox{ (mod }p\mbox{)}$ (\textit{mp\_reduce}) \\ -10. $res \leftarrow 1$ \\ -\\ -Start Sliding Window. \\ -11. $mode \leftarrow 0, bitcnt \leftarrow 1, buf \leftarrow 0, digidx \leftarrow x.used - 1, bitcpy \leftarrow 0, bitbuf \leftarrow 0$ \\ -12. Loop \\ -\hspace{3mm}12.1 $bitcnt \leftarrow bitcnt - 1$ \\ -\hspace{3mm}12.2 If $bitcnt = 0$ then do \\ -\hspace{6mm}12.2.1 If $digidx = -1$ goto step 13. \\ -\hspace{6mm}12.2.2 $buf \leftarrow x_{digidx}$ \\ -\hspace{6mm}12.2.3 $digidx \leftarrow digidx - 1$ \\ -\hspace{6mm}12.2.4 $bitcnt \leftarrow lg(\beta)$ \\ -Continued on next page. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm s\_mp\_exptmod} -\end{figure} - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{s\_mp\_exptmod} (\textit{continued}). \\ -\textbf{Input}. mp\_int $a$, $b$ and $c$ \\ -\textbf{Output}. $y \equiv g^x \mbox{ (mod }p\mbox{)}$ \\ -\hline \\ -\hspace{3mm}12.3 $y \leftarrow (buf >> (lg(\beta) - 1))$ AND $1$ \\ -\hspace{3mm}12.4 $buf \leftarrow buf << 1$ \\ -\hspace{3mm}12.5 if $mode = 0$ and $y = 0$ then goto step 12. \\ -\hspace{3mm}12.6 if $mode = 1$ and $y = 0$ then do \\ -\hspace{6mm}12.6.1 $res \leftarrow res^2$ \\ -\hspace{6mm}12.6.2 $res \leftarrow res \mbox{ (mod }p\mbox{)}$ \\ -\hspace{6mm}12.6.3 Goto step 12. \\ -\hspace{3mm}12.7 $bitcpy \leftarrow bitcpy + 1$ \\ -\hspace{3mm}12.8 $bitbuf \leftarrow bitbuf + (y << (winsize - bitcpy))$ \\ -\hspace{3mm}12.9 $mode \leftarrow 2$ \\ -\hspace{3mm}12.10 If $bitcpy = winsize$ then do \\ -\hspace{6mm}Window is full so perform the squarings and single multiplication. \\ -\hspace{6mm}12.10.1 for $ix$ from $0$ to $winsize -1$ do \\ -\hspace{9mm}12.10.1.1 $res \leftarrow res^2$ \\ -\hspace{9mm}12.10.1.2 $res \leftarrow res \mbox{ (mod }p\mbox{)}$ \\ -\hspace{6mm}12.10.2 $res \leftarrow res \cdot M_{bitbuf}$ \\ -\hspace{6mm}12.10.3 $res \leftarrow res \mbox{ (mod }p\mbox{)}$ \\ -\hspace{6mm}Reset the window. \\ -\hspace{6mm}12.10.4 $bitcpy \leftarrow 0, bitbuf \leftarrow 0, mode \leftarrow 1$ \\ -\\ -No more windows left. Check for residual bits of exponent. \\ -13. If $mode = 2$ and $bitcpy > 0$ then do \\ -\hspace{3mm}13.1 for $ix$ form $0$ to $bitcpy - 1$ do \\ -\hspace{6mm}13.1.1 $res \leftarrow res^2$ \\ -\hspace{6mm}13.1.2 $res \leftarrow res \mbox{ (mod }p\mbox{)}$ \\ -\hspace{6mm}13.1.3 $bitbuf \leftarrow bitbuf << 1$ \\ -\hspace{6mm}13.1.4 If $bitbuf$ AND $2^{winsize} \ne 0$ then do \\ -\hspace{9mm}13.1.4.1 $res \leftarrow res \cdot M_{1}$ \\ -\hspace{9mm}13.1.4.2 $res \leftarrow res \mbox{ (mod }p\mbox{)}$ \\ -14. $y \leftarrow res$ \\ -15. Clear $res$, $mu$ and the $M$ array. \\ -16. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm s\_mp\_exptmod (continued)} -\end{figure} - -\textbf{Algorithm s\_mp\_exptmod.} -This algorithm computes the $x$'th power of $g$ modulo $p$ and stores the result in $y$. It takes advantage of the Barrett reduction -algorithm to keep the product small throughout the algorithm. - -The first two steps determine the optimal window size based on the number of bits in the exponent. The larger the exponent the -larger the window size becomes. After a window size $winsize$ has been chosen an array of $2^{winsize}$ mp\_int variables is allocated. This -table will hold the values of $g^x \mbox{ (mod }p\mbox{)}$ for $2^{winsize - 1} \le x < 2^{winsize}$. - -After the table is allocated the first power of $g$ is found. Since $g \ge p$ is allowed it must be first reduced modulo $p$ to make -the rest of the algorithm more efficient. The first element of the table at $2^{winsize - 1}$ is found by squaring $M_1$ successively $winsize - 2$ -times. The rest of the table elements are found by multiplying the previous element by $M_1$ modulo $p$. - -Now that the table is available the sliding window may begin. The following list describes the functions of all the variables in the window. -\begin{enumerate} -\item The variable $mode$ dictates how the bits of the exponent are interpreted. -\begin{enumerate} - \item When $mode = 0$ the bits are ignored since no non-zero bit of the exponent has been seen yet. For example, if the exponent were simply - $1$ then there would be $lg(\beta) - 1$ zero bits before the first non-zero bit. In this case bits are ignored until a non-zero bit is found. - \item When $mode = 1$ a non-zero bit has been seen before and a new $winsize$-bit window has not been formed yet. In this mode leading $0$ bits - are read and a single squaring is performed. If a non-zero bit is read a new window is created. - \item When $mode = 2$ the algorithm is in the middle of forming a window and new bits are appended to the window from the most significant bit - downwards. -\end{enumerate} -\item The variable $bitcnt$ indicates how many bits are left in the current digit of the exponent left to be read. When it reaches zero a new digit - is fetched from the exponent. -\item The variable $buf$ holds the currently read digit of the exponent. -\item The variable $digidx$ is an index into the exponents digits. It starts at the leading digit $x.used - 1$ and moves towards the trailing digit. -\item The variable $bitcpy$ indicates how many bits are in the currently formed window. When it reaches $winsize$ the window is flushed and - the appropriate operations performed. -\item The variable $bitbuf$ holds the current bits of the window being formed. -\end{enumerate} - -All of step 12 is the window processing loop. It will iterate while there are digits available form the exponent to read. The first step -inside this loop is to extract a new digit if no more bits are available in the current digit. If there are no bits left a new digit is -read and if there are no digits left than the loop terminates. - -After a digit is made available step 12.3 will extract the most significant bit of the current digit and move all other bits in the digit -upwards. In effect the digit is read from most significant bit to least significant bit and since the digits are read from leading to -trailing edges the entire exponent is read from most significant bit to least significant bit. - -At step 12.5 if the $mode$ and currently extracted bit $y$ are both zero the bit is ignored and the next bit is read. This prevents the -algorithm from having to perform trivial squaring and reduction operations before the first non-zero bit is read. Step 12.6 and 12.7-10 handle -the two cases of $mode = 1$ and $mode = 2$ respectively. - -FIGU,expt_state,Sliding Window State Diagram - -By step 13 there are no more digits left in the exponent. However, there may be partial bits in the window left. If $mode = 2$ then -a Left-to-Right algorithm is used to process the remaining few bits. - -EXAM,bn_s_mp_exptmod.c - -Lines @26,if@ through @40,}@ determine the optimal window size based on the length of the exponent in bits. The window divisions are sorted -from smallest to greatest so that in each \textbf{if} statement only one condition must be tested. For example, by the \textbf{if} statement -on line @32,if@ the value of $x$ is already known to be greater than $140$. - -The conditional piece of code beginning on line @42,define@ allows the window size to be restricted to five bits. This logic is used to ensure -the table of precomputed powers of $G$ remains relatively small. - -The for loop on line @49,for@ initializes the $M$ array while lines @59,mp_init@ and @62,mp_reduce@ compute the value of $\mu$ required for -Barrett reduction. - --- More later. - -\section{Quick Power of Two} -Calculating $b = 2^a$ can be performed much quicker than with any of the previous algorithms. Recall that a logical shift left $m << k$ is -equivalent to $m \cdot 2^k$. By this logic when $m = 1$ a quick power of two can be achieved. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_2expt}. \\ -\textbf{Input}. integer $b$ \\ -\textbf{Output}. $a \leftarrow 2^b$ \\ -\hline \\ -1. $a \leftarrow 0$ \\ -2. If $a.alloc < \lfloor b / lg(\beta) \rfloor + 1$ then grow $a$ appropriately. \\ -3. $a.used \leftarrow \lfloor b / lg(\beta) \rfloor + 1$ \\ -4. $a_{\lfloor b / lg(\beta) \rfloor} \leftarrow 1 << (b \mbox{ mod } lg(\beta))$ \\ -5. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_2expt} -\end{figure} - -\textbf{Algorithm mp\_2expt.} - -EXAM,bn_mp_2expt.c - -\chapter{Higher Level Algorithms} - -This chapter discusses the various higher level algorithms that are required to complete a well rounded multiple precision integer package. These -routines are less performance oriented than the algorithms of chapters five, six and seven but are no less important. - -The first section describes a method of integer division with remainder that is universally well known. It provides the signed division logic -for the package. The subsequent section discusses a set of algorithms which allow a single digit to be the 2nd operand for a variety of operations. -These algorithms serve mostly to simplify other algorithms where small constants are required. The last two sections discuss how to manipulate -various representations of integers. For example, converting from an mp\_int to a string of character. - -\section{Integer Division with Remainder} -MARK,DIVISION - -Integer division aside from modular exponentiation is most intensive algorithm to compute. - - -\section{Single Digit Helpers} -\subsection{Single Digit Addition} -\subsection{Single Digit Subtraction} -\subsection{Single Digit Multiplication} -\subsection{Single Digit Division} -\subsection{Single Digit Modulo} -\subsection{Single Digit Root Extraction} -\section{Random Number Generation} -\section{Formatted Output} -\subsection{Getting The Output Size} -\subsection{Generating Radix-n Output} -\subsection{Reading Radix-n Input} -\section{Unformatted Output} -\subsection{Getting The Output Size} -\subsection{Generating Output} -\subsection{Reading Input} - -\chapter{Number Theoretic Algorithms} -\section{Greatest Common Divisor} -\section{Least Common Multiple} -\section{Jacobi Symbol Computation} -\section{Modular Inverse} -MARK,MODINV -\subsection{General Case} -\subsection{Odd Moduli} -\section{Primality Tests} -\subsection{Trial Division} -\subsection{The Fermat Test} -\subsection{The Miller-Rabin Test} -\subsection{Primality Test in a Bottle} -\subsection{The Next Prime} -\section{Root Extraction} - -\backmatter -\appendix -\begin{thebibliography}{ABCDEF} -\bibitem[1]{TAOCPV2} -Donald Knuth, \textit{The Art of Computer Programming}, Third Edition, Volume Two, Seminumerical Algorithms, Addison-Wesley, 1998 - -\bibitem[2]{HAC} -A. Menezes, P. van Oorschot, S. Vanstone, \textit{Handbook of Applied Cryptography}, CRC Press, 1996 - -\bibitem[3]{ROSE} -Michael Rosing, \textit{Implementing Elliptic Curve Cryptography}, Manning Publications, 1999 - -\bibitem[4]{COMBA} -Paul G. Comba, \textit{Exponentiation Cryptosystems on the IBM PC}. IBM Systems Journal 29(4): 526-538 (1990) - -\bibitem[5]{KARA} -A. Karatsuba, Doklay Akad. Nauk SSSR 145 (1962), pp.293-294 - -\bibitem[6]{KARAP} -Andre Weimerskirch and Christof Paar, \textit{Generalizations of the Karatsuba Algorithm for Polynomial Multiplication}, Submitted to Design, Codes and Cryptography, March 2002 - -\bibitem[7]{BARRETT} -Paul Barrett, \textit{Implementing the Rivest Shamir and Adleman Public Key Encryption Algorithm on a Standard Digital Signal Processor}, Advances in Cryptology, Crypto '86, Springer-Verlag. - -\bibitem[8]{MONT} -P.L.Montgomery. \textit{Modular multiplication without trial division}. Mathematics of Computation, 44(170):519-521, April 1985. - -\bibitem[9]{DRMET} -Chae Hoon Lim and Pil Joong Lee, \textit{Generating Efficient Primes for Discrete Log Cryptosystems}, POSTECH Information Research Laboratories - -\bibitem[10]{MMB} -J. Daemen and R. Govaerts and J. Vandewalle, \textit{Block ciphers based on Modular Arithmetic}, State and {P}rogress in the {R}esearch of {C}ryptography, 1993, pp. 80-89 - -\end{thebibliography} - -\input{tommath.ind} - -\chapter{Appendix} -\subsection*{Appendix A -- Source Listing of tommath.h} - -The following is the source listing of the header file ``tommath.h'' for the LibTomMath project. It contains many of -the definitions used throughout the code such as \textbf{mp\_int}, \textbf{MP\_PREC} and so on. The header is -presented here for completeness. - -LIST,tommath.h - -\end{document} \ No newline at end of file diff --git a/tommath.tex b/tommath.tex deleted file mode 100644 index cd2a97e..0000000 --- a/tommath.tex +++ /dev/null @@ -1,8141 +0,0 @@ -\documentclass[b5paper]{book} -\usepackage{hyperref} -\usepackage{makeidx} -\usepackage{amssymb} -\usepackage{color} -\usepackage{alltt} -\usepackage{graphicx} -\usepackage{layout} -\def\union{\cup} -\def\intersect{\cap} -\def\getsrandom{\stackrel{\rm R}{\gets}} -\def\cross{\times} -\def\cat{\hspace{0.5em} \| \hspace{0.5em}} -\def\catn{$\|$} -\def\divides{\hspace{0.3em} | \hspace{0.3em}} -\def\nequiv{\not\equiv} -\def\approx{\raisebox{0.2ex}{\mbox{\small $\sim$}}} -\def\lcm{{\rm lcm}} -\def\gcd{{\rm gcd}} -\def\log{{\rm log}} -\def\ord{{\rm ord}} -\def\abs{{\mathit abs}} -\def\rep{{\mathit rep}} -\def\mod{{\mathit\ mod\ }} -\renewcommand{\pmod}[1]{\ ({\rm mod\ }{#1})} -\newcommand{\floor}[1]{\left\lfloor{#1}\right\rfloor} -\newcommand{\ceil}[1]{\left\lceil{#1}\right\rceil} -\def\Or{{\rm\ or\ }} -\def\And{{\rm\ and\ }} -\def\iff{\hspace{1em}\Longleftrightarrow\hspace{1em}} -\def\implies{\Rightarrow} -\def\undefined{{\rm ``undefined"}} -\def\Proof{\vspace{1ex}\noindent {\bf Proof:}\hspace{1em}} -\let\oldphi\phi -\def\phi{\varphi} -\def\Pr{{\rm Pr}} -\newcommand{\str}[1]{{\mathbf{#1}}} -\def\F{{\mathbb F}} -\def\N{{\mathbb N}} -\def\Z{{\mathbb Z}} -\def\R{{\mathbb R}} -\def\C{{\mathbb C}} -\def\Q{{\mathbb Q}} -\definecolor{DGray}{gray}{0.5} -\newcommand{\emailaddr}[1]{\mbox{$<${#1}$>$}} -\def\twiddle{\raisebox{0.3ex}{\mbox{\tiny $\sim$}}} -\def\gap{\vspace{0.5ex}} -\makeindex -\begin{document} -\frontmatter -\pagestyle{empty} -\title{Multiple-Precision Integer Arithmetic, \\ A Case Study Involving the LibTomMath Project \\ - DRAFT - } -\author{\mbox{ -%\begin{small} -\begin{tabular}{c} -Tom St Denis \\ -Algonquin College \\ -\\ -Mads Rasmussen \\ -Open Communications Security \\ -\\ -Greg Rose \\ -QUALCOMM Australia \\ -\end{tabular} -%\end{small} -} -} -\maketitle -This text in its entirety is copyright \copyright{}2003 by Tom St Denis. It may not be redistributed -electronically or otherwise without the sole permission of the author. The text is freely redistributable as long as -it is packaged along with the LibTomMath library in a non-commercial project. Contact the -author for other redistribution rights. - -This text corresponds to the v0.17 release of the LibTomMath project. - -\begin{alltt} -Tom St Denis -111 Banning Rd -Ottawa, Ontario -K2L 1C3 -Canada - -Phone: 1-613-836-3160 -Email: tomstdenis@iahu.ca -\end{alltt} - -This text is formatted to the international B5 paper size of 176mm wide by 250mm tall using the \LaTeX{} -{\em book} macro package and the Perl {\em booker} package. - -\tableofcontents -\listoffigures -\chapter*{Preface} -Blah. - -\mainmatter -\pagestyle{headings} -\chapter{Introduction} -\section{Multiple Precision Arithmetic} -\subsection{The Need for Multiple Precision Arithmetic} -The most prevalent use for multiple precision arithmetic (\textit{often referred to as bignum math}) is within public -key cryptography. Algorithms such as RSA, Diffie-Hellman and Elliptic Curve Cryptography require large integers in order to -resist known cryptanalytic attacks. Typical modern programming languages such as C and Java only provide small -single-precision data types which are incapable of precisely representing integers which are often hundreds of bits long. - -For example, consider multiplying $1,234,567$ by $9,876,543$ in C with an ``unsigned long'' data type. With an -x86 machine the result is $4,136,875,833$ while the true result is $12,193,254,061,881$. The original inputs -were approximately $21$ and $24$ bits respectively. If the C language cannot multiply two relatively small values -together precisely how does anyone expect it to multiply two values that are considerably larger? - -Most advancements in fast multiple precision arithmetic stem from the desire for faster cryptographic primitives. However, cryptography -is not the only field of study that can benefit from fast large integer routines. Another auxiliary use for multiple precision integers is -high precision floating point data types. The basic IEEE standard floating point type is made up of an integer mantissa $q$ and an exponent $e$. -Numbers are given in the form $n = q \cdot b^e$ where $b = 2$ is specified. Since IEEE is meant to be implemented in -hardware the precision of the mantissa is often fairly small (\textit{23, 48 and 64 bits}). Since the mantissa is merely an -integer a large multiple precision integer could be used. In effect very high precision floating point arithmetic -could be performed. This would be useful where scientific applications must minimize the total output error over long simulations. - -\subsection{Multiple Precision Arithmetic} -\index{multiple precision} -Multiple precision arithmetic attempts to the solve the shortcomings of single precision data types such as those from -the C and Java programming languages. In essence multiple precision arithmetic is a set of operations that can be -performed on members of an algebraic group whose precision is not fixed. The algorithms when implemented to be multiple -precision can allow a developer to work with any practical precision required. - -Typically the arithmetic over the ring of integers denoted by $\Z$ is performed by routines that are collectively and -casually referred to as ``bignum'' routines. However, it is possible to have rings of polynomials as well typically -denoted by $\Z/p\Z \left [ X \right ]$ which could have variable precision (\textit{or degree}). This text will -discuss implementation of the former, however implementing polynomial basis routines should be relatively easy after reading this text. - -\subsection{Benefits of Multiple Precision Arithmetic} -\index{precision} \index{accuracy} -Precision of the real value to a given precision is defined loosely as the proximity of the real value to a given representation. -Accuracy is defined as the reproducibility of the result. For example, the calculation $1/3 = 0.25$ is imprecise but can be accurate provided -it is reproducible. - -The benefit of multiple precision representations over single precision representations is that -often no precision is lost while representing the result of an operation which requires excess precision. For example, -the multiplication of two $n$-bit integers requires at least $2n$ bits to represent the result. A multiple precision -system would augment the precision of the destination to accomodate the result while a single precision system would -truncate excess bits to maintain a fixed level of precision. - -Multiple precision representations allow for the precision to be very high (\textit{if not exacting}) but at a cost of -modest computer resources. The only reasonable case where a multiple precision system will lose precision is when -emulating a floating point data type. However, with multiple precision integer arithmetic no precision is lost. - -\subsection{Basis of Operations} -At the heart of all multiple precision integer operations are the ``long-hand'' algorithms we all learned as children -in grade school. For example, to multiply $1,234$ by $981$ the student is not taught to memorize the times table for -$1,234$, instead they are taught how to long-multiply. That is to multiply each column using simple single digit -multiplications, line up the partial results, and add the resulting products by column. The representation that most -are familiar with is known as decimal or formally as radix-10. A radix-$n$ representation simply means there are -$n$ possible values per digit. For example, binary would be a radix-2 representation. - -In essence computer based multiple precision arithmetic is very much the same. The most notable difference is the usage -of a binary friendly radix. That is to use a radix of the form $2^k$ where $k$ is typically the size of a machine -register. Also occasionally more optimal algorithms are used to perform certain operations such as multiplication and -squaring instead of traditional long-hand algorithms. - -\section{Purpose of This Text} -The purpose of this text is to instruct the reader regarding how to implement multiple precision algorithms. That is -to not only explain the core theoretical algorithms but also the various ``house keeping'' tasks that are neglected by -authors of other texts on the subject. Texts such as \cite[HAC]{HAC} and \cite{TAOCPV2} give considerably detailed -explanations of the theoretical aspects of the algorithms and very little regarding the practical aspects. - -How an algorithm is explained and how it is actually implemented are two very different -realities. For example, algorithm 14.7 on page 594 of HAC lists a relatively simple algorithm for performing multiple -precision integer addition. However, what the description lacks is any discussion concerning the fact that the two -integer inputs may be of differing magnitudes. Similarly the division routine (\textit{Algorithm 14.20, pp. 598}) -does not discuss how to handle sign or handle the dividend's decreasing magnitude in the main loop (\textit{Step \#3}). - -As well as the numerous practical oversights both of the texts do not discuss several key optimal algorithms required -such as ``Comba'' and Karatsuba multipliers and fast modular inversion. These optimal algorithms are vital to achieve -any form of useful performance in non-trivial applications. - -To solve this problem the focus of this text is on the practical aspects of implementing the algorithms that -constitute a multiple precision integer package with light discussions on the theoretical aspects. As a case -study the ``LibTomMath''\footnote{Available freely at http://math.libtomcrypt.org} package is used to demonstrate -algorithms with implementations that have been field tested and work very well. - -\section{Discussion and Notation} -\subsection{Notation} -A multiple precision integer of $n$-digits shall be denoted as $x = (x_n ... x_1 x_0)_{ \beta }$ to be the -multiple precision notation for the integer $x \equiv \sum_{i=0}^{n} x_i\beta^i$. The elements of the array $x$ are -said to be the radix $\beta$ digits of the integer. For example, $x = (1,2,3)_{10}$ would represent the -integer $1\cdot 10^2 + 2\cdot10^1 + 3\cdot10^0 = 123$. - -A ``mp\_int'' shall refer to a composite structure which contains the digits of the integer as well as auxilary data -required to manipulate the data. These additional members are discussed in chapter three. For the purposes of this text -a ``multiple precision integer'' and a ``mp\_int'' are synonymous. - -\index{single-precision} \index{double-precision} \index{mp\_digit} \index{mp\_word} -For the purposes of this text a single-precision variable must be able to represent integers in the range $0 \le x < 2 \beta$ while -a double-precision variable must be able to represent integers in the range $0 \le x < 2 \beta^2$. Within the source code that will be -presented the data type \textbf{mp\_digit} will represent a single-precision type while \textbf{mp\_word} will represent a -double-precision type. In several algorithms (\textit{notably the Comba routines}) temporary results -will be stored in a double-precision arrays. For the purposes of this text $x_j$ will refer to the -$j$'th digit of a single-precision array and $\hat x_j$ will refer to the $j$'th digit of a double-precision -array. - -The $\lfloor \mbox{ } \rfloor$ brackets represent a value truncated and rounded down to the nearest integer. The $\lceil \mbox{ } \rceil$ brackets -represent a value truncated and rounded up to the nearest integer. Typically when the $/$ division symbol is used the intention is to perform an integer -division. For example, $5/2 = 2$ which will often be written as $\lfloor 5/2 \rfloor = 2$ for clarity. When a value is presented as a fraction -such as $5 \over 2$ a real value division is implied. - -\subsection{Work Effort} -\index{big-O} -To measure the efficiency of various algorithms a modified big-O notation is used. In this system all -single precision operations are considered to have the same cost\footnote{Except where explicitly noted.}. -That is a single precision addition, multiplication and division are assumed to take the same time to -complete. While this is generally not true in practice it will simplify the discussions considerably. - -Some algorithms have slight advantages over others which is why some constants will not be removed in -the notation. For example, a normal multiplication requires $O(n^2)$ work while a squaring requires -$O({{n^2 + n}\over 2})$ work. In standard big-O notation these would be said to be equivalent. However, in the -context of the this text the magnitude of the inputs will not approach an infinite size. This means the conventional limit -notation wisdom does not apply to the cancellation of constants. - -Throughout the discussions various ``work levels'' will be discussed. These levels are the $O(1)$, -$O(n)$, $O(n^2)$, ..., $O(n^k)$ work efforts. For example, operations at the $O(n^k)$ ``level'' are said to be -executed more frequently than operations at the $O(n^m)$ ``level'' when $k > m$. Obviously most optimizations will pay -off the most at the higher levels since they represent the bulk of the effort required. - -\section{Exercises} -Within the more advanced chapters a section will be set aside to give the reader some challenging exercises. These exercises are not -designed to be prize winning problems, but to be thought provoking. Wherever possible the problems are forward minded stating -problems that will be answered in subsequent chapters. The reader is encouraged to finish the exercises as they appear to get a -better understanding of the subject material. - -Similar to the exercises of \cite{TAOCPV2} as explained on pp.\textit{ix} these exercises are given a scoring system. However, unlike -\cite{TAOCPV2} the problems do not get nearly as hard as often. The scoring of these exercises ranges from one (\textit{the easiest}) to -five (\textit{the hardest}). The following table sumarizes the scoring. - -\vspace{5mm} -\begin{tabular}{cl} -$\left [ 1 \right ]$ & An easy problem that should only take the reader a manner of \\ - & minutes to solve. Usually does not involve much computer time. \\ - & \\ -$\left [ 2 \right ]$ & An easy problem that involves a marginal amount of computer \\ - & time usage. Usually requires a program to be written to \\ - & solve the problem. \\ - & \\ -$\left [ 3 \right ]$ & A moderately hard problem that requires a non-trivial amount \\ - & of work. Usually involves trivial research and development of \\ - & new theory from the perspective of a student. \\ - & \\ -$\left [ 4 \right ]$ & A moderately hard problem that involves a non-trivial amount \\ - & of work and research. The solution to which will demonstrate \\ - & a higher mastery of the subject matter. \\ - & \\ -$\left [ 5 \right ]$ & A hard problem that involves concepts that are non-trivial. \\ - & Solutions to these problems will demonstrate a complete mastery \\ - & of the given subject. \\ - & \\ -\end{tabular} - -Essentially problems at the first level are meant to be simple questions that the reader can answer quickly without programming a solution or -devising new theory. These problems are quick tests to see if the material is understood. Problems at the second level are also -designed to be easy but will require a program or algorithm to be implemented to arrive at the answer. - -Problems at the third level are meant to be a bit more difficult. Often the answer is fairly obvious but arriving at an exacting solution -requires some thought and skill. These problems will almost always involve devising a new algorithm or implementing a variation of -another algorithm. - -Problems at the fourth level are meant to be even more difficult as well as involve some research. The reader will most likely not know -the answer right away nor will this text provide the exact details of the answer (\textit{or at least not until a subsequent chapter}). Problems -at the fifth level are meant to be the hardest problems relative to all the other problems in the chapter. People who can correctly -answer fifth level problems have a mastery of the subject matter at hand. - -Often problems will be tied together. The purpose of this is to start a chain of thought that will be discussed in future chapters. The reader -is encouraged to answer the follow-up problems and try to draw the relevence of problems. - -\chapter{Introduction to LibTomMath} - -\section{What is LibTomMath?} -LibTomMath is a free and open source multiple precision library written in portable ISO C source code. By portable it is -meant that the library does not contain any code that is computer platform dependent or otherwise problematic to use on any -given platform. The library has been successfully tested under numerous operating systems including Solaris, MacOS, Windows, -Linux, PalmOS and on standalone hardware such as the Gameboy Advance. The library is designed to contain enough -functionality to be able to develop applications such as public key cryptosystems. - -\section{Goals of LibTomMath} - -Even though the library is written entirely in portable ISO C considerable care has been taken to -optimize the algorithm implementations within the library. Specifically the code has been written to work well with -the GNU C Compiler (\textit{GCC}) on both x86 and ARMv4 processors. Wherever possible highly efficient -algorithms (\textit{such as Karatsuba multiplication, sliding window exponentiation and Montgomery reduction}) have -been provided to make the library as efficient as possible. Even with the optimal and sometimes specialized -algorithms that have been included the Application Programing Interface (\textit{API}) has been kept as simple as possible. -Often generic place holder routines will make use of specialized algorithms automatically without the developer's -attention. One such example is the generic multiplication algorithm \textbf{mp\_mul()} which will automatically use -Karatsuba multiplication if the inputs are of a specific size. - -Making LibTomMath as efficient as possible is not the only goal of the LibTomMath project. Ideally the library should -be source compatible with another popular library which makes it more attractive for developers to use. In this case the -MPI library was used as a API template for all the basic functions. - -The project is also meant to act as a learning tool for students. The logic being that no easy-to-follow ``bignum'' -library exists which can be used to teach computer science students how to perform fast and reliable multiple precision -arithmetic. To this end the source code has been given quite a few comments and algorithm discussion points. Often routines have -more comments than lines of code. - -\section{Choice of LibTomMath} -LibTomMath was chosen as the case study of this text not only because the author of both projects is one and the same but -for more worthy reasons. Other libraries such as GMP, MPI, LIP and OpenSSL have multiple precision -integer arithmetic routines but would not be ideal for this text for reasons as will be explained in the -following sub-sections. - -\subsection{Code Base} -The LibTomMath code base is all portable ISO C source code. This means that there are no platform dependent conditional -segments of code littered throughout the source. This clean and uncluttered approach to the library means that a -developer can more readily ascertain the true intent of a given section of source code without trying to keep track of -what conditional code will be used. - -The code base of LibTomMath is also well organized. Each function is in its own separate source code file -which allows the reader to find a given function very fast. When compiled with GCC for the x86 processor the entire -library is a mere 87,760 bytes (\textit{$116,182$ bytes for ARMv4 processors}). This includes every single function -LibTomMath provides from basic arithmetic to various number theoretic functions such as modular exponentiation, various -reduction algorithms and Jacobi symbol computation. - -By comparison MPI which has fewer functions than LibTomMath compiled with the same conditions is 45,429 bytes -(\textit{$54,536$ for ARMv4}). GMP which has rather large collection of functions with the default configuration on an -x86 Athlon is 2,950,688 bytes. Note that while LibTomMath has fewer functions than GMP it has been used as the sole basis -for several public key cryptosystems without having to seek additional outside functions to supplement the library. - -\subsection{API Simplicity} -LibTomMath is designed after the MPI library and shares the API design. Quite often programs that use MPI will build -with LibTomMath without change. The function names are relatively straight forward as to what they perform. Almost all of the -functions except for a few minor exceptions which as will be discussed are for good reasons share the same parameter passing -convention. The learning curve is fairly shallow with the API provided which is an extremely valuable benefit for the -student and developer alike. - -The LIP library is an example of a library with an API that is awkward to work with. LIP uses function names that are often ``compressed'' to -illegible short hand. LibTomMath does not share this fault. - -\subsection{Optimizations} -While LibTomMath is certainly not the fastest library (\textit{GMP often beats LibTomMath by a factor of two}) it does -feature a set of optimal algorithms for tasks ranging from modular reduction to squaring. GMP and LIP also feature -such optimizations while MPI only uses baseline algorithms with no optimizations. - -LibTomMath is almost always an order of magnitude faster than the MPI library at computationally expensive tasks such as modular -exponentiation. In the grand scheme of ``bignum'' libraries LibTomMath is faster than the average library and usually -slower than the best libraries such as GMP and OpenSSL by a small factor. - -\subsection{Portability and Stability} -LibTomMath will build ``out of the box'' on any platform equipped with a modern version of the GNU C Compiler -(\textit{GCC}). This means that without changes the library will build without configuration or setting up any -variables. LIP and MPI will build ``out of the box'' as well but have numerous known bugs. Most notably the author of -MPI is not working on his library anymore. - -GMP requires a configuration script to run and will not build out of the box. GMP and LibTomMath are still in active -development and are very stable across a variety of platforms. - -\subsection{Choice} -LibTomMath is a relatively compact, well documented, highly optimized and portable library which seems only natural for -the case study of this text. Various source files from the LibTomMath project will be included within the text. However, the -reader is encouraged to download their own copy of the library to actually be able to work with the library. - -\chapter{Getting Started} -\section{Library Basics} -To begin the design of a multiple precision integer library a primitive data type and a series of primitive algorithms must be established. A data -type that will hold the information required to maintain a multiple precision integer must be designed. With this basic data type of a series -of low level algorithms for initializing, clearing, growing and optimizing multiple precision integers can be developed to form the basis of -the entire library of algorithms. - -\section{What is a Multiple Precision Integer?} -Recall that most programming languages (\textit{in particular C}) only have fixed precision data types that on their own cannot be used -to represent values larger than their precision alone will allow. The purpose of multiple precision algorithms is to use these fixed precision -data types to create multiple precision integers which may represent values that are much larger. - -As a well known analogy, school children are taught how to form numbers larger than nine by prepending more radix ten digits. In the decimal system -the largest value is only $9$ since the digits may only have values from $0$ to $9$. However, by concatenating digits together larger numbers -may be represented. Computer based multiple precision arithmetic is essentially the same concept except with a different radix. - -What most people probably do not think about explicitly are the various other attributes that describe a multiple precision integer. For example, -the integer $154_{10}$ has two immediately obvious properties. First, the integer is positive, that is the sign of this particular integer -is positive as oppose to negative. Second, the integer has three digits in its representation. There is an additional property that the integer -posesses that does not concern pencil-and-paper arithmetic. The third property is how many digits are allowed for the integer. - -The human analogy of this third property is ensuring there is enough space on the paper to right the integer. Computers must maintain a -strict control on memory usage with respect to the digits of a multiple precision integer. These three properties make up what is known -as a multiple precision integer or mp\_int for short. - -\subsection{The mp\_int structure} -The mp\_int structure is the ISO C based manifestation of what represents a multiple precision integer. The ISO C standard does not provide for -any such data type but it does provide for making composite data types known as structures. The following is the structure definition -used within LibTomMath. - -\index{mp\_int} -\begin{verbatim} -typedef struct { - int used, alloc, sign; - mp_digit *dp; -} mp_int; -\end{verbatim} - -The mp\_int structure can be broken down as follows. - -\begin{enumerate} -\item The \textbf{used} parameter denotes how many digits of the array \textbf{dp} contain the digits used to represent -a given integer. The \textbf{used} count must not exceed the \textbf{alloc} count. - -\item The array \textbf{dp} holds the digits that represent the given integer. It is padded with $\textbf{alloc} - \textbf{used}$ zero -digits. - -\item The \textbf{alloc} parameter denotes how -many digits are available in the array to use by functions before it has to increase in size. When the \textbf{used} count -of a result would exceed the \textbf{alloc} count all of the algorithms will automatically increase the size of the -array to accommodate the precision of the result. - -\item The \textbf{sign} parameter denotes the sign as either zero/positive (\textbf{MP\_ZPOS}) or negative (\textbf{MP\_NEG}). -\end{enumerate} - -\section{Argument Passing} -A convention of argument passing must be adopted early on in the development of any library. Making the function prototypes -consistent will help eliminate many headaches in the future as the library grows to significant complexity. In LibTomMath the multiple precision -integer functions accept parameters from left to right as pointers to mp\_int structures. That means that the source operands are -placed on the left and the destination on the right. Consider the following examples. - -\begin{verbatim} - mp_mul(&a, &b, &c); /* c = a * b */ - mp_add(&a, &b, &a); /* a = a + b */ - mp_sqr(&a, &b); /* b = a * a */ -\end{verbatim} - -The left to right order is a fairly natural way to implement the functions since it lets the developer read aloud the -functions and make sense of them. For example, the first function would read ``multiply a and b and store in c''. - -Certain libraries (\textit{LIP by Lenstra for instance}) accept parameters the other way around. That is the destination -on the left and arguments on the right. In truth it is entirely a matter of preference. In the case of LibTomMath the -convention from the MPI library has been adopted. - -Another very useful design consideration is whether to allow argument sources to also be a destination. For example, the -second example (\textit{mp\_add}) adds $a$ to $b$ and stores in $a$. This is an important feature to implement since it -allows the higher up functions to cut down on the number of variables. However, to implement this feature specific -care has to be given to ensure the destination is not modified before the source is fully read. - -\section{Return Values} -A well implemented library, no matter what its purpose, should trap as many runtime errors as possible and return them to the -caller. By catching runtime errors a library can be guaranteed to prevent undefined behaviour. In a multiple precision -library the only errors that can occur occur are related to inappropriate inputs (\textit{division by zero for instance}) or -memory allocation errors. - -In LibTomMath any function that can cause a runtime error will return an error as an \textbf{int} data type with one of the -following values. - -\index{MP\_OKAY} \index{MP\_VAL} \index{MP\_MEM} -\begin{center} -\begin{tabular}{|l|l|} -\hline \textbf{Value} & \textbf{Meaning} \\ -\hline \textbf{MP\_OKAY} & The function was successful \\ -\hline \textbf{MP\_VAL} & One of the input value(s) was invalid \\ -\hline \textbf{MP\_MEM} & The function ran out of heap memory \\ -\hline -\end{tabular} -\end{center} - -When an error is detected within a function it should free any memory it allocated and return as soon as possible. The goal -is to leave the system in the same state the system was when the function was called. Error checking with this style of API is fairly simple. - -\begin{verbatim} - int err; - if ((err = mp_add(&a, &b, &c)) != MP_OKAY) { - printf("Error: %d\n", err); - exit(EXIT_FAILURE); - } -\end{verbatim} - -The GMP library uses C style \textit{signals} to flag errors which is of questionable use. Not all errors are fatal -and it was not deemed ideal by the author of LibTomMath to force developers to have signal handlers for such cases. - -\section{Initialization and Clearing} -The logical starting point when actually writing multiple precision integer functions is the initialization and -clearing of the integers. These two functions will be used by far the most throughout the algorithms whenever -temporary integers are required. - -Given the basic mp\_int structure an initialization routine must first allocate memory to hold the digits of -the integer. Often it is optimal to allocate a sufficiently large pre-set number of digits even considering -the initial integer will represent zero. If only a single digit were allocated quite a few re-allocations -would occur for the majority of inputs. There is a tradeoff between how many default digits to allocate -and how many re-allocations are tolerable. - -If the memory for the digits has been successfully allocated then the rest of the members of the structure must -be initialized. Since the initial state is to represent a zero integer the digits allocated must all be zeroed. The -\textbf{used} count set to zero and \textbf{sign} set to \textbf{MP\_ZPOS}. - -\subsection{Initializing an mp\_int} -To initialize an mp\_int the mp\_init algorithm shall be used. The purpose of this algorithm is to allocate -the memory required and initialize the integer to a default representation of zero. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_init}. \\ -\textbf{Input}. An mp\_int $a$ \\ -\textbf{Output}. Allocate memory for the digits and set to a zero state. \\ -\hline \\ -1. Allocate memory for \textbf{MP\_PREC} digits. \\ -2. If the allocation failed then return(\textit{MP\_MEM}) \\ -3. for $n$ from $0$ to $MP\_PREC - 1$ do \\ -\hspace{3mm}3.1 $a_n \leftarrow 0$\\ -4. $a.sign \leftarrow MP\_ZPOS$\\ -5. $a.used \leftarrow 0$\\ -6. $a.alloc \leftarrow MP\_PREC$\\ -7. Return(\textit{MP\_OKAY})\\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_init} -\end{figure} - -\textbf{Algorithm mp\_init.} -The \textbf{MP\_PREC} variable is a simple constant used to dictate minimal precision of allocated integers. It is ideally at least equal to $32$ but -can be any reasonable power of two. Steps one and two allocate the memory and account for it. If the allocation fails the algorithm returns -immediately to signal the failure. Step three will ensure that all the digits are in the default state of zero. Finally steps -four through six set the default settings of the \textbf{sign}, \textbf{used} and \textbf{alloc} members of the mp\_int structure. - -\index{bn\_mp\_init.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_init.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* init a new bigint */ -018 int -019 mp_init (mp_int * a) -020 \{ -021 /* allocate ram required and clear it */ -022 a->dp = OPT_CAST calloc (sizeof (mp_digit), MP_PREC); -023 if (a->dp == NULL) \{ -024 return MP_MEM; -025 \} -026 -027 /* set the used to zero, allocated digits to the default precision -028 * and sign to positive */ -029 a->used = 0; -030 a->alloc = MP_PREC; -031 a->sign = MP_ZPOS; -032 -033 return MP_OKAY; -034 \} -\end{alltt} -\end{small} - -The \textbf{OPT\_CAST} type cast on line 22 is designed to allow C++ compilers to build the code out of -the box. Microsoft C V5.00 is known to cause problems without the cast. Also note that if the memory -allocation fails the other members of the mp\_int will be in an undefined state. The code from -line 29 to line 31 sets the default state for a mp\_int which is zero, positive and no used digits. - -\subsection{Clearing an mp\_int} -When an mp\_int is no longer required the memory allocated for it can be cleared from the heap with -the mp\_clear algorithm. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_clear}. \\ -\textbf{Input}. An mp\_int $a$ \\ -\textbf{Output}. The memory for $a$ is cleared. \\ -\hline \\ -1. If $a$ has been previously freed then return(\textit{MP\_OKAY}). \\ -2. Free the digits of $a$ and mark $a$ as freed. \\ -3. $a.used \leftarrow 0$ \\ -4. $a.alloc \leftarrow 0$ \\ -5. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_clear} -\end{figure} - -\textbf{Algorithm mp\_clear.} -In steps one and two the memory for the digits are only free'd if they had not been previously released before. -This is more of concern for the implementation since it is used to prevent ``double-free'' errors. It also helps catch -code errors where mp\_ints are used after being cleared. Similarly steps three and four set the -\textbf{used} and \textbf{alloc} to known values which would be easy to spot during debugging. For example, if an mp\_int is expected -to be non-zero and its \textbf{used} member is observed to be zero (\textit{due to being cleared}) then an obvious bug in the code has been -spotted. - -\index{bn\_mp\_clear.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_clear.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* clear one (frees) */ -018 void -019 mp_clear (mp_int * a) -020 \{ -021 if (a->dp != NULL) \{ -022 -023 /* first zero the digits */ -024 memset (a->dp, 0, sizeof (mp_digit) * a->used); -025 -026 /* free ram */ -027 free (a->dp); -028 -029 /* reset members to make debugging easier */ -030 a->dp = NULL; -031 a->alloc = a->used = 0; -032 \} -033 \} -\end{alltt} -\end{small} - -The \textbf{if} statement on line 21 prevents the heap from being corrupted if a user double-frees an -mp\_int. For example, a trivial case of this bug would be as follows. - -\begin{verbatim} -mp_int a; -mp_init(&a); -mp_clear(&a); -mp_clear(&a); -\end{verbatim} - -Without that check the code would try to free the memory allocated for the digits twice which will cause most standard C -libraries to cause a fault. Also by setting the pointer to \textbf{NULL} it helps debug code that may inadvertently -free the mp\_int before it is truly not needed. The allocated digits are set to zero before being freed on line 24. -This is ideal for cryptographic situations where the mp\_int is a secret parameter. - -The following snippet is an example of using both the init and clear functions. - -\begin{small} -\begin{verbatim} -#include -#include -#include -int main(void) -{ - mp_int num; - int err; - - /* init the bignum */ - if ((err = mp_init(&num)) != MP_OKAY) { - printf("Error: %d\n", err); - return EXIT_FAILURE; - } - - /* do work with it ... */ - - /* clear up */ - mp_clear(&num); - - return EXIT_SUCCESS; -} -\end{verbatim} -\end{small} - -\section{Other Initialization Routines} - -It is often helpful to have specialized initialization algorithms to simplify the design of other algorithms. For example, an -initialization followed by a copy is a common operation when temporary copies of integers are required. It is quite -beneficial to have a series of simple helper functions available. - -\subsection{Initializing Variable Sized mp\_int Structures} -Occasionally the number of digits required will be known in advance of an initialization. In these -cases the mp\_init\_size algorithm can be of use. The purpose of this algorithm is similar to mp\_init except that -it will allocate \textit{at least} a specified number of digits. This is ideal to prevent re-allocations when the -input size is known. - -\newpage\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_init\_size}. \\ -\textbf{Input}. An mp\_int $a$ and the requested number of digits $b$\\ -\textbf{Output}. $a$ is initialized to hold at least $b$ digits. \\ -\hline \\ -1. $u \leftarrow b\mbox{ (mod }MP\_PREC\mbox{)}$ \\ -2. $v \leftarrow b + 2 \cdot MP\_PREC - u$ \\ -3. Allocate $v$ digits. \\ -4. If the allocation failed then return(\textit{MP\_MEM}). \\ -5. for $n$ from $0$ to $v - 1$ do \\ -\hspace{3mm}5.1 $a_n \leftarrow 0$ \\ -6. $a.sign \leftarrow MP\_ZPOS$\\ -7. $a.used \leftarrow 0$\\ -8. $a.alloc \leftarrow v$\\ -9. Return(\textit{MP\_OKAY})\\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_init\_size} -\end{figure} - -\textbf{Algorithm mp\_init\_size.} -The value of $v$ is calculated to be at least the requested amount of digits $b$ plus additional padding. The padding is calculated -to be at least \textbf{MP\_PREC} digits plus enough digits to make the digit count a multiple of \textbf{MP\_PREC}. This padding is used to -prevent trivial allocations from becoming a bottleneck in the rest of the algorithms that depend on this. - -\index{bn\_mp\_init\_size.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_init\_size.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* init a mp_init and grow it to a given size */ -018 int -019 mp_init_size (mp_int * a, int size) -020 \{ -021 -022 /* pad size so there are always extra digits */ -023 size += (MP_PREC * 2) - (size & (MP_PREC - 1)); -024 -025 /* alloc mem */ -026 a->dp = OPT_CAST calloc (sizeof (mp_digit), size); -027 if (a->dp == NULL) \{ -028 return MP_MEM; -029 \} -030 a->used = 0; -031 a->alloc = size; -032 a->sign = MP_ZPOS; -033 -034 return MP_OKAY; -035 \} -\end{alltt} -\end{small} - -Line 23 will ensure that the number of digits actually allocated is padded up to the next multiple of -\textbf{MP\_PREC} plus an additional \textbf{MP\_PREC}. This ensures that the number of allocated digit is -always greater than the amount requested. As a result it prevents many trivial memory allocations. The value of -\textbf{MP\_PREC} is defined in ``tommath.h'' and must be a power of two. - -\subsection{Creating a Clone} -Another common sequence of operations is to make a local temporary copy of an argument. To initialize then copy a mp\_int will be known as -creating a clone. This is useful within functions that need to modify an integer argument but do not wish to actually modify the original copy. -The mp\_init\_copy algorithm will perform this very task. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_init\_copy}. \\ -\textbf{Input}. An mp\_int $a$ and $b$\\ -\textbf{Output}. $a$ is initialized to be a copy of $b$. \\ -\hline \\ -1. Init $a$. (\textit{mp\_init}) \\ -2. If the init of $a$ was unsuccessful return(\textit{MP\_MEM}) \\ -3. Copy $b$ to $a$. (\textit{mp\_copy}) \\ -4. Return the status of the copy operation. \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_init\_copy} -\end{figure} - -\textbf{Algorithm mp\_init\_copy.} -This algorithm will initialize a mp\_int variable and copy another previously initialized mp\_int variable into it. The algorithm will -detect when the initialization fails and returns the error to the calling algorithm. As such this algorithm will perform two operations -in one step. - -\index{bn\_mp\_init\_copy.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_init\_copy.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* creates "a" then copies b into it */ -018 int -019 mp_init_copy (mp_int * a, mp_int * b) -020 \{ -021 int res; -022 -023 if ((res = mp_init (a)) != MP_OKAY) \{ -024 return res; -025 \} -026 return mp_copy (b, a); -027 \} -\end{alltt} -\end{small} - -This will initialize \textbf{a} and make it a verbatim copy of the contents of \textbf{b}. Note that -\textbf{a} will have its own memory allocated which means that \textbf{b} may be cleared after the call -and \textbf{a} will be left intact. - -\subsection{Multiple Integer Initializations And Clearings} -Occasionally a function will require a series of mp\_int data types to be made available. The mp\_init\_multi algorithm -is provided to simplify such cases. The purpose of this algorithm is to initialize a variable length array of mp\_int -structures at once. As a result algorithms that require multiple integers only has to use -one algorithm to initialize all the mp\_int variables. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_init\_multi}. \\ -\textbf{Input}. Variable length array of mp\_int variables of length $k$. \\ -\textbf{Output}. The array is initialized such that each each mp\_int is ready to use. \\ -\hline \\ -1. for $n$ from 0 to $k - 1$ do \\ -\hspace{+3mm}1.1. Initialize the $n$'th mp\_int (\textit{mp\_init}) \\ -\hspace{+3mm}1.2. If initialization failed then do \\ -\hspace{+6mm}1.2.1. for $j$ from $0$ to $n$ do \\ -\hspace{+9mm}1.2.1.1. Free the $j$'th mp\_int (\textit{mp\_clear}) \\ -\hspace{+6mm}1.2.2. Return(\textit{MP\_MEM}) \\ -2. Return(\textit{MP\_OKAY}) \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_init\_multi} -\end{figure} - -\textbf{Algorithm mp\_init\_multi.} -The algorithm will initialize the array of mp\_int variables one at a time. As soon as an runtime error is detected (\textit{step 1.2}) all of -the previously initialized variables are cleared. The goal is an ``all or nothing'' initialization which allows for quick recovery from runtime -errors. - -Similarly to clear a variable length array of mp\_int structures the mp\_clear\_multi algorithm will be used. - -Consider the following snippet which demonstrates how to use both routines. -\begin{small} -\begin{verbatim} -#include -#include -#include -int main(void) -{ - mp_int num1, num2, num3; - int err; - - if ((err = mp_init_multi(&num1, &num2, &num3, NULL)) !- MP_OKAY) { - printf("Error: %d\n", err); - return EXIT_FAILURE; - } - - /* at this point num1/num2/num3 are ready */ - - /* free them */ - mp_clear_multi(&num1, &num2, &num3, NULL); - - return EXIT_SUCCESS; -} -\end{verbatim} -\end{small} - -Note how both lists are terminated with the \textbf{NULL} variable. This indicates to the algorithms to stop fetching parameters off -of the stack. If it is not present the functions will most likely cause a segmentation fault. - -\index{bn\_mp\_multi.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_multi.c -\vspace{-3mm} -\begin{alltt} -016 #include -017 -018 int mp_init_multi(mp_int *mp, ...) -019 \{ -020 mp_err res = MP_OKAY; /* Assume ok until proven otherwise */ -021 int n = 0; /* Number of ok inits */ -022 mp_int* cur_arg = mp; -023 va_list args; -024 -025 va_start(args, mp); /* init args to next argument from caller */ -026 while (cur_arg != NULL) \{ -027 if (mp_init(cur_arg) != MP_OKAY) \{ -028 /* Oops - error! Back-track and mp_clear what we already -029 succeeded in init-ing, then return error. -030 */ -031 va_list clean_args; -032 -033 /* end the current list */ -034 va_end(args); -035 -036 /* now start cleaning up */ -037 cur_arg = mp; -038 va_start(clean_args, mp); -039 while (n--) \{ -040 mp_clear(cur_arg); -041 cur_arg = va_arg(clean_args, mp_int*); -042 \} -043 va_end(clean_args); -044 res = MP_MEM; -045 break; -046 \} -047 n++; -048 cur_arg = va_arg(args, mp_int*); -049 \} -050 va_end(args); -051 return res; /* Assumed ok, if error flagged above. */ -052 \} -053 -054 void mp_clear_multi(mp_int *mp, ...) -055 \{ -056 mp_int* next_mp = mp; -057 va_list args; -058 va_start(args, mp); -059 while (next_mp != NULL) \{ -060 mp_clear(next_mp); -061 next_mp = va_arg(args, mp_int*); -062 \} -063 va_end(args); -064 \} -\end{alltt} -\end{small} - -Both routines are implemented in the same source file since they are typically used in conjunction with each other. - -\section{Maintenance} -A small useful collection of mp\_int maintenance functions will also prove useful. - -\subsection{Augmenting Integer Precision} -When storing a value in an mp\_int sufficient digits must be available to accomodate the entire value without -loss of precision. Quite often the size of the array given by the \textbf{alloc} member is large enough to simply -increase the \textbf{used} digit count. However, when the size of the array is too small it must be re-sized -appropriately to accomodate the result. The mp\_grow algorithm will provide this functionality. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_grow}. \\ -\textbf{Input}. An mp\_int $a$ and an integer $b$. \\ -\textbf{Output}. $a$ is expanded to accomodate $b$ digits. \\ -\hline \\ -1. if $a.alloc \ge b$ then return(\textit{MP\_OKAY}) \\ -2. $u \leftarrow b\mbox{ (mod }MP\_PREC\mbox{)}$ \\ -3. $v \leftarrow b + 2 \cdot MP\_PREC - u$ \\ -4. Re-Allocate the array of digits $a$ to size $v$ \\ -5. If the allocation failed then return(\textit{MP\_MEM}). \\ -6. for n from a.alloc to $v - 1$ do \\ -\hspace{+3mm}6.1 $a_n \leftarrow 0$ \\ -7. $a.alloc \leftarrow v$ \\ -8. Return(\textit{MP\_OKAY}) \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_grow} -\end{figure} - -\textbf{Algorithm mp\_grow.} -Step one will prevent a re-allocation from being performed if it was not required. This is useful to prevent mp\_ints -from growing excessively in code that erroneously calls mp\_grow. Similar to mp\_init\_size the requested digit count -is padded to provide more digits than requested. - -In step four it is assumed that the reallocation leaves the lower $a.alloc$ digits intact. This is much akin to how the -\textit{realloc} function from the standard C library works. Since the newly allocated digits are assumed to contain -undefined values they are also initially zeroed. - -\index{bn\_mp\_grow.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_grow.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* grow as required */ -018 int -019 mp_grow (mp_int * a, int size) -020 \{ -021 int i; -022 -023 /* if the alloc size is smaller alloc more ram */ -024 if (a->alloc < size) \{ -025 /* ensure there are always at least MP_PREC digits extra on top */ -026 size += (MP_PREC * 2) - (size & (MP_PREC - 1)); -027 -028 a->dp = OPT_CAST realloc (a->dp, sizeof (mp_digit) * size); -029 if (a->dp == NULL) \{ -030 return MP_MEM; -031 \} -032 -033 /* zero excess digits */ -034 i = a->alloc; -035 a->alloc = size; -036 for (; i < a->alloc; i++) \{ -037 a->dp[i] = 0; -038 \} -039 \} -040 return MP_OKAY; -041 \} -\end{alltt} -\end{small} - -The first step is to see if we actually need to perform a re-allocation at all. This is tested for on line -24. Similar to mp\_init\_size the same code on line 26 was used to resize the -digits requested. A simple for loop from line 34 to line 38 will zero all digits that were above the -old \textbf{alloc} limit to make sure the integer is in a known state. - -\subsection{Clamping Excess Digits} -When a function anticipates a result will be $n$ digits it is simpler to assume this is true within the body of -the function. For example, a multiplication of a $i$ digit number by a $j$ digit produces a result of at most -$i + j$ digits. It is entirely possible that the result is $i + j - 1$ though, with no final carry into the last -position. However, suppose the destination had to be first expanded (\textit{via mp\_grow}) to accomodate $i + j - 1$ -digits than further expanded to accomodate the final carry. That would be a considerable waste of time since heap -operations are relatively slow. - -The ideal solution is to always assume the result is $i + j$ and fix up the \textbf{used} count after the function -terminates. This way a single heap operation (\textit{at most}) is required. However, if the result was not checked -there would be an excess high order zero digit. - -For example, suppose the product of two integers was $x_n = (0x_{n-1}x_{n-2}...x_0)_{\beta}$. The leading zero digit -will not contribute to the precision of the result. In fact, through subsequent operations more leading zero digits would -accumulate to the point the size of the integer would be prohibitive. As a result even though the precision is very -low the representation is excessively large. - -The mp\_clamp algorithm is designed to solve this very problem. It will trim leading zeros by decrementing the -\textbf{used} count until a non-zero leading digit is found. Also in this system, zero is considered to be a positive -number which means that if the \textbf{used} count is decremented to zero the sign must be set to \textbf{MP\_ZPOS}. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_clamp}. \\ -\textbf{Input}. An mp\_int $a$ \\ -\textbf{Output}. Any excess leading zero digits of $a$ are removed \\ -\hline \\ -1. while $a.used > 0$ and $a_{a.used - 1} = 0$ do \\ -\hspace{+3mm}1.1 $a.used \leftarrow a.used - 1$ \\ -2. if $a.used = 0$ then do \\ -\hspace{+3mm}2.1 $a.sign \leftarrow MP\_ZPOS$ \\ -\hline \\ -\end{tabular} -\end{center} -\caption{Algorithm mp\_clamp} -\end{figure} - -\textbf{Algorithm mp\_clamp.} -As can be expected this algorithm is very simple. The loop on step one is expected to iterate only once or twice at -the most. For example, this will happen in cases where there is not a carry to fill the last position. Step two fixes the sign for -when all of the digits are zero to ensure that the mp\_int is valid at all times. - -\index{bn\_mp\_clamp.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_clamp.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* trim unused digits -018 * -019 * This is used to ensure that leading zero digits are -020 * trimed and the leading "used" digit will be non-zero -021 * Typically very fast. Also fixes the sign if there -022 * are no more leading digits -023 */ -024 void -025 mp_clamp (mp_int * a) -026 \{ -027 while (a->used > 0 && a->dp[a->used - 1] == 0) \{ -028 --(a->used); -029 \} -030 if (a->used == 0) \{ -031 a->sign = MP_ZPOS; -032 \} -033 \} -\end{alltt} -\end{small} - -Note on line 27 how to test for the \textbf{used} count is made on the left of the \&\& operator. In the C programming -language the terms to \&\& are evaluated left to right with a boolean short-circuit if any condition fails. This is -important since if the \textbf{used} is zero the test on the right would fetch below the array. That is obviously -undesirable. The parenthesis on line 28 is used to make sure the \textbf{used} count is decremented and not -the pointer ``a''. - -\section*{Exercises} -\begin{tabular}{cl} -$\left [ 1 \right ]$ & Discuss the relevance of the \textbf{used} member of the mp\_int structure. \\ - & \\ -$\left [ 1 \right ]$ & Discuss the consequences of not using padding when performing allocations. \\ - & \\ -$\left [ 2 \right ]$ & Estimate an ideal value for \textbf{MP\_PREC} when performing 1024-bit RSA \\ - & encryption when $\beta = 2^{28}$. \\ - & \\ -$\left [ 1 \right ]$ & Discuss the relevance of the algorithm mp\_clamp. What does it prevent? \\ - & \\ -$\left [ 1 \right ]$ & Give an example of when the algorithm mp\_init\_copy might be useful. \\ - & \\ -\end{tabular} - - -\chapter{Basic Operations} -\section{Copying an Integer} -After the various house-keeping routines are in place, simple algorithms can be designed to take advantage of them. Being able -to make a verbatim copy of an integer is a very useful function to have. To copy an integer the mp\_copy algorithm will be used. - -\newpage\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_copy}. \\ -\textbf{Input}. An mp\_int $a$ and $b$. \\ -\textbf{Output}. Store a copy of $a$ in $b$. \\ -\hline \\ -1. Check if $a$ and $b$ point to the same location in memory. \\ -2. If true then return(\textit{MP\_OKAY}). \\ -3. If $b.alloc < a.used$ then grow $b$ to $a.used$ digits. (\textit{mp\_grow}) \\ -4. If failed to grow then return(\textit{MP\_MEM}). \\ -5. for $n$ from 0 to $a.used - 1$ do \\ -\hspace{3mm}5.1 $b_{n} \leftarrow a_{n}$ \\ -6. if $a.used < b.used - 1$ then \\ -\hspace{3mm}6.1. for $n$ from $a.used$ to $b.used - 1$ do \\ -\hspace{6mm}6.1.1 $b_{n} \leftarrow 0$ \\ -7. $b.used \leftarrow a.used$ \\ -8. $b.sign \leftarrow a.sign$ \\ -9. return(\textit{MP\_OKAY}) \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_copy} -\end{figure} - -\textbf{Algorithm mp\_copy.} -Step 1 and 2 make sure that the two mp\_ints are unique. This allows the user to call the copy function with -potentially the same input and not waste time. Step 3 and 4 ensure that the destination is large enough to -hold a copy of the input $a$. Note that the \textbf{used} member of $b$ may be smaller than the \textbf{used} -member of $a$ but a memory re-allocation is only required if the \textbf{alloc} member of $b$ is smaller. This -prevents trivial memory reallocations. - -Step 5 copies the digits from $a$ to $b$ while step 6 ensures that if initially $\vert b \vert > \vert a \vert$, -the more significant digits of $b$ will be zeroed. Finally steps 7 and 8 copies the \textbf{used} and \textbf{sign} members over -which completes the copy operation. - -\index{bn\_mp\_copy.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_copy.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* copy, b = a */ -018 int -019 mp_copy (mp_int * a, mp_int * b) -020 \{ -021 int res, n; -022 -023 /* if dst == src do nothing */ -024 if (a == b) \{ -025 return MP_OKAY; -026 \} -027 -028 /* grow dest */ -029 if ((res = mp_grow (b, a->used)) != MP_OKAY) \{ -030 return res; -031 \} -032 -033 /* zero b and copy the parameters over */ -034 \{ -035 register mp_digit *tmpa, *tmpb; -036 -037 /* pointer aliases */ -038 tmpa = a->dp; -039 tmpb = b->dp; -040 -041 /* copy all the digits */ -042 for (n = 0; n < a->used; n++) \{ -043 *tmpb++ = *tmpa++; -044 \} -045 -046 /* clear high digits */ -047 for (; n < b->used; n++) \{ -048 *tmpb++ = 0; -049 \} -050 \} -051 b->used = a->used; -052 b->sign = a->sign; -053 return MP_OKAY; -054 \} -\end{alltt} -\end{small} - -Source lines 23-31 do the initial house keeping. That is to see if the input is unique and if so to -make sure there is enough room. If not enough space is available it returns the error and leaves the destination variable -intact. - -The inner loop of the copy operation is contained between lines 34 and 50. Many LibTomMath routines are designed with this source code style -in mind, making aliases to shorten lengthy pointers (\textit{see line 38 and 39}) for rapid use. Also the -use of nested braces creates a simple way to denote various portions of code that reside on various work levels. Here, the copy loop is at the -$O(n)$ level. - -\section{Zeroing an Integer} -Reseting an mp\_int to the default state is a common step in many algorithms. The mp\_zero algorithm will be the algorithm used to -perform this task. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_zero}. \\ -\textbf{Input}. An mp\_int $a$ \\ -\textbf{Output}. Zero the contents of $a$ \\ -\hline \\ -1. $a.used \leftarrow 0$ \\ -2. $a.sign \leftarrow$ MP\_ZPOS \\ -3. for $n$ from 0 to $a.alloc - 1$ do \\ -\hspace{3mm}3.1 $a_n \leftarrow 0$ \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_zero} -\end{figure} - -\textbf{Algorithm mp\_zero.} -This algorithm simply resets a mp\_int to the default state. - -\index{bn\_mp\_zero.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_zero.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* set to zero */ -018 void -019 mp_zero (mp_int * a) -020 \{ -021 a->sign = MP_ZPOS; -022 a->used = 0; -023 memset (a->dp, 0, sizeof (mp_digit) * a->alloc); -024 \} -\end{alltt} -\end{small} - -After the function is completed, all of the digits are zeroed, the \textbf{used} count is zeroed and the -\textbf{sign} variable is set to \textbf{MP\_ZPOS}. - -\section{Sign Manipulation} -\subsection{Absolute Value} -With the mp\_int representation of an integer, calculating the absolute value is trivial. The mp\_abs algorithm will compute -the absolute value of an mp\_int. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_abs}. \\ -\textbf{Input}. An mp\_int $a$ \\ -\textbf{Output}. Computes $b = \vert a \vert$ \\ -\hline \\ -1. Copy $a$ to $b$. (\textit{mp\_copy}) \\ -2. If the copy failed return(\textit{MP\_MEM}). \\ -3. $b.sign \leftarrow MP\_ZPOS$ \\ -4. Return(\textit{MP\_OKAY}) \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_abs} -\end{figure} - -\textbf{Algorithm mp\_abs.} -This algorithm computes the absolute of an mp\_int input. As can be expected the algorithm is very trivial. - -\index{bn\_mp\_abs.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_abs.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* b = |a| -018 * -019 * Simple function copies the input and fixes the sign to positive -020 */ -021 int -022 mp_abs (mp_int * a, mp_int * b) -023 \{ -024 int res; -025 if ((res = mp_copy (a, b)) != MP_OKAY) \{ -026 return res; -027 \} -028 b->sign = MP_ZPOS; -029 return MP_OKAY; -030 \} -\end{alltt} -\end{small} - -\subsection{Integer Negation} -With the mp\_int representation of an integer, calculating the negation is also trivial. The mp\_neg algorithm will compute -the negative of an mp\_int input. - -\newpage\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_neg}. \\ -\textbf{Input}. An mp\_int $a$ \\ -\textbf{Output}. Computes $b = -a$ \\ -\hline \\ -1. Copy $a$ to $b$. (\textit{mp\_copy}) \\ -2. If the copy failed return(\textit{MP\_MEM}). \\ -3. If $a.sign = MP\_ZPOS$ then do \\ -\hspace{3mm}3.1 $b.sign = MP\_NEG$. \\ -4. else do \\ -\hspace{3mm}4.1 $b.sign = MP\_ZPOS$. \\ -5. Return(\textit{MP\_OKAY}) \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_neg} -\end{figure} - -\textbf{Algorithm mp\_neg.} -This algorithm computes the negation of an input. - -\index{bn\_mp\_neg.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_neg.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* b = -a */ -018 int -019 mp_neg (mp_int * a, mp_int * b) -020 \{ -021 int res; -022 if ((res = mp_copy (a, b)) != MP_OKAY) \{ -023 return res; -024 \} -025 b->sign = (a->sign == MP_ZPOS) ? MP_NEG : MP_ZPOS; -026 return MP_OKAY; -027 \} -\end{alltt} -\end{small} - -\section{Small Constants} -\subsection{Setting Small Constants} -Often a mp\_int must be set to a relatively small value such as $1$ or $2$. For these cases the mp\_set algorithm is useful. - -\newpage\begin{figure} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_set}. \\ -\textbf{Input}. An mp\_int $a$ and a digit $b$ \\ -\textbf{Output}. Make $a$ equivalent to $b$ \\ -\hline \\ -1. Zero $a$ (\textit{mp\_zero}). \\ -2. $a_0 \leftarrow b \mbox{ (mod }\beta\mbox{)}$ \\ -3. $a.used \leftarrow \left \lbrace \begin{array}{ll} - 1 & \mbox{if }a_0 > 0 \\ - 0 & \mbox{if }a_0 = 0 - \end{array} \right .$ \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_set} -\end{figure} - -\textbf{Algorithm mp\_set.} -This algorithm sets a mp\_int to a small single digit value. Step number 1 ensures that the integer is reset to the default state. The -single digit is set (\textit{modulo $\beta$}) and the \textbf{used} count is adjusted accordingly. - -\index{bn\_mp\_set.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_set.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* set to a digit */ -018 void -019 mp_set (mp_int * a, mp_digit b) -020 \{ -021 mp_zero (a); -022 a->dp[0] = b & MP_MASK; -023 a->used = (a->dp[0] != 0) ? 1 : 0; -024 \} -\end{alltt} -\end{small} - -Line 21 calls mp\_zero() to clear the mp\_int and reset the sign. Line 22 copies the digit -into the least significant location. Note the usage of a new constant \textbf{MP\_MASK}. This constant is used to quickly -reduce an integer modulo $\beta$. Since $\beta$ is of the form $2^k$ for any suitable $k$ it suffices to perform a binary AND with -$MP\_MASK = 2^k - 1$ to perform the reduction. Finally line 23 will set the \textbf{used} member with respect to the -digit actually set. This function will always make the integer positive. - -One important limitation of this function is that it will only set one digit. The size of a digit is not fixed, meaning source that uses -this function should take that into account. Meaning that only trivially small constants can be set using this function. - -\subsection{Setting Large Constants} -To overcome the limitations of the mp\_set algorithm the mp\_set\_int algorithm is provided. It accepts a ``long'' -data type as input and will always treat it as a 32-bit integer. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_set\_int}. \\ -\textbf{Input}. An mp\_int $a$ and a ``long'' integer $b$ \\ -\textbf{Output}. Make $a$ equivalent to $b$ \\ -\hline \\ -1. Zero $a$ (\textit{mp\_zero}) \\ -2. for $n$ from 0 to 7 do \\ -\hspace{3mm}2.1 $a \leftarrow a \cdot 16$ (\textit{mp\_mul2d}) \\ -\hspace{3mm}2.2 $u \leftarrow \lfloor b / 2^{4(7 - n)} \rfloor \mbox{ (mod }16\mbox{)}$\\ -\hspace{3mm}2.3 $a_0 \leftarrow a_0 + u$ \\ -\hspace{3mm}2.4 $a.used \leftarrow a.used + 1$ \\ -3. Clamp excess used digits (\textit{mp\_clamp}) \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_set\_int} -\end{figure} - -\textbf{Algorithm mp\_set\_int.} -The algorithm performs eight iterations of a simple loop where in each iteration four bits from the source are added to the -mp\_int. Step 2.1 will multiply the current result by sixteen making room for four more bits in the less significant positions. In step 2.2 the -next four bits from the source are extracted and are added to the mp\_int. The \textbf{used} digit count is -incremented to reflect the addition. The \textbf{used} digit counter is incremented since if any of the leading digits were zero the mp\_int would have -zero digits used and the newly added four bits would be ignored. - -Excess zero digits are trimmed in steps 2.1 and 3 by using higher level algorithms mp\_mul2d and mp\_clamp. - -\index{bn\_mp\_set\_int.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_set\_int.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* set a 32-bit const */ -018 int -019 mp_set_int (mp_int * a, unsigned int b) -020 \{ -021 int x, res; -022 -023 mp_zero (a); -024 /* set four bits at a time */ -025 for (x = 0; x < 8; x++) \{ -026 /* shift the number up four bits */ -027 if ((res = mp_mul_2d (a, 4, a)) != MP_OKAY) \{ -028 return res; -029 \} -030 -031 /* OR in the top four bits of the source */ -032 a->dp[0] |= (b >> 28) & 15; -033 -034 /* shift the source up to the next four bits */ -035 b <<= 4; -036 -037 /* ensure that digits are not clamped off */ -038 a->used += 1; -039 \} -040 mp_clamp (a); -041 return MP_OKAY; -042 \} -\end{alltt} -\end{small} - -This function sets four bits of the number at a time to handle all practical \textbf{DIGIT\_BIT} sizes. The weird -addition on line 38 ensures that the newly added in bits are added to the number of digits. While it may not -seem obvious as to why the digit counter does not grow exceedingly large it is because of the shift on line 27 -as well as the call to mp\_clamp() on line 40. Both functions will clamp excess leading digits which keeps -the number of used digits low. - -\section{Comparisons} -\subsection{Unsigned Comparisions} -Comparing a multiple precision integer is performed with the exact same algorithm used to compare two decimal numbers. For example, -to compare $1,234$ to $1,264$ the digits are extracted by their positions. That is we compare $1 \cdot 10^3 + 2 \cdot 10^2 + 3 \cdot 10^1 + 4 \cdot 10^0$ -to $1 \cdot 10^3 + 2 \cdot 10^2 + 6 \cdot 10^1 + 4 \cdot 10^0$ by comparing single digits at a time starting with the highest magnitude -positions. If any leading digit of one integer is greater than a digit in the same position of another integer then obviously it must be greater. - -The first comparision routine that will be developed is the unsigned magnitude compare which will perform a comparison based on the digits of two -mp\_int variables alone. It will ignore the sign of the two inputs. Such a function is useful when an absolute comparison is required or if the -signs are known to agree in advance. - -To facilitate working with the results of the comparison functions three constants are required. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{|r|l|} -\hline \textbf{Constant} & \textbf{Meaning} \\ -\hline \textbf{MP\_GT} & Greater Than \\ -\hline \textbf{MP\_EQ} & Equal To \\ -\hline \textbf{MP\_LT} & Less Than \\ -\hline -\end{tabular} -\end{center} -\caption{Comparison Return Codes} -\end{figure} - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_cmp\_mag}. \\ -\textbf{Input}. Two mp\_ints $a$ and $b$. \\ -\textbf{Output}. Unsigned comparison results ($a$ to the left of $b$). \\ -\hline \\ -1. If $a.used > b.used$ then return(\textit{MP\_GT}) \\ -2. If $a.used < b.used$ then return(\textit{MP\_LT}) \\ -3. for n from $a.used - 1$ to 0 do \\ -\hspace{+3mm}3.1 if $a_n > b_n$ then return(\textit{MP\_GT}) \\ -\hspace{+3mm}3.2 if $a_n < b_n$ then return(\textit{MP\_LT}) \\ -4. Return(\textit{MP\_EQ}) \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_cmp\_mag} -\end{figure} - -\textbf{Algorithm mp\_cmp\_mag.} -By saying ``$a$ to the left of $b$'' it is meant that the comparison is with respect to $a$, that is if $a$ is greater than $b$ it will return -\textbf{MP\_GT} and similar with respect to when $a = b$ and $a < b$. The first two steps compare the number of digits used in both $a$ and $b$. -Obviously if the digit counts differ there would be an imaginary zero digit in the smaller number where the leading digit of the larger number is. -If both have the same number of digits than the actual digits themselves must be compared starting at the leading digit. - -By step three both inputs must have the same number of digits so its safe to start from either $a.used - 1$ or $b.used - 1$ and count down to -the zero'th digit. If after all of the digits have been compared, no difference is found, the algorithm returns \textbf{MP\_EQ}. - -\index{bn\_mp\_cmp\_mag.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_cmp\_mag.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* compare maginitude of two ints (unsigned) */ -018 int -019 mp_cmp_mag (mp_int * a, mp_int * b) -020 \{ -021 int n; -022 -023 /* compare based on # of non-zero digits */ -024 if (a->used > b->used) \{ -025 return MP_GT; -026 \} -027 -028 if (a->used < b->used) \{ -029 return MP_LT; -030 \} -031 -032 /* compare based on digits */ -033 for (n = a->used - 1; n >= 0; n--) \{ -034 if (a->dp[n] > b->dp[n]) \{ -035 return MP_GT; -036 \} -037 -038 if (a->dp[n] < b->dp[n]) \{ -039 return MP_LT; -040 \} -041 \} -042 return MP_EQ; -043 \} -\end{alltt} -\end{small} - -The two if statements on lines 24 and 28 compare the number of digits in the two inputs. These two are performed before all of the digits -are compared since it is a very cheap test to perform and can potentially save considerable time. The implementation given is also not valid -without those two statements. $b.alloc$ may be smaller than $a.used$, meaning that undefined values will be read from $b$ past the end of the -array of digits. - -\subsection{Signed Comparisons} -Comparing with sign considerations is also fairly critical in several routines (\textit{division for example}). Based on an unsigned magnitude -comparison a trivial signed comparison algorithm can be written. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_cmp}. \\ -\textbf{Input}. Two mp\_ints $a$ and $b$ \\ -\textbf{Output}. Signed Comparison Results ($a$ to the left of $b$) \\ -\hline \\ -1. if $a.sign = MP\_NEG$ and $b.sign = MP\_ZPOS$ then return(\textit{MP\_LT}) \\ -2. if $a.sign = MP\_ZPOS$ and $b.sign = MP\_NEG$ then return(\textit{MP\_GT}) \\ -3. if $a.sign = MP\_NEG$ then \\ -\hspace{+3mm}3.1 Return the unsigned comparison of $b$ and $a$ (\textit{mp\_cmp\_mag}) \\ -4 Otherwise \\ -\hspace{+3mm}4.1 Return the unsigned comparison of $a$ and $b$ \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_cmp} -\end{figure} - -\textbf{Algorithm mp\_cmp.} -The first two steps compare the signs of the two inputs. If the signs do not agree then it can return right away with the appropriate -comparison code. When the signs are equal the digits of the inputs must be compared to determine the correct result. In step -three the unsigned comparision flips the order of the arguments since they are both negative. For instance, if $-a > -b$ then -$\vert a \vert < \vert b \vert$. Step number four will compare the two when they are both positive. - -\index{bn\_mp\_cmp.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_cmp.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* compare two ints (signed)*/ -018 int -019 mp_cmp (mp_int * a, mp_int * b) -020 \{ -021 /* compare based on sign */ -022 if (a->sign == MP_NEG && b->sign == MP_ZPOS) \{ -023 return MP_LT; -024 \} -025 -026 if (a->sign == MP_ZPOS && b->sign == MP_NEG) \{ -027 return MP_GT; -028 \} -029 -030 /* compare digits */ -031 if (a->sign == MP_NEG) \{ -032 /* if negative compare opposite direction */ -033 return mp_cmp_mag(b, a); -034 \} else \{ -035 return mp_cmp_mag(a, b); -036 \} -037 \} -\end{alltt} -\end{small} - -The two if statements on lines 22 and 26 perform the initial sign comparison. If the signs are not the equal then which ever -has the positive sign is larger. At line 31, the inputs are compared based on magnitudes. If the signs were both negative then -the unsigned comparison is performed in the opposite direction (\textit{line 33}). Otherwise, the signs are assumed to -be both positive and a forward direction unsigned comparison is performed. - -\section*{Exercises} -\begin{tabular}{cl} -$\left [ 2 \right ]$ & Modify algorithm mp\_set\_int to accept as input a variable length array of bits. \\ - & \\ -$\left [ 3 \right ]$ & Give the probability that algorithm mp\_cmp\_mag will have to compare $k$ digits \\ - & of two random digits (of equal magnitude) before a difference is found. \\ - & \\ -$\left [ 1 \right ]$ & Suggest a simple method to speed up the implementation of mp\_cmp\_mag based \\ - & on the observations made in the previous problem. \\ - & -\end{tabular} - -\chapter{Basic Arithmetic} -\section{Building Blocks} -At this point algorithms for initialization, clearing, zeroing, copying, comparing and setting small constants have been -established. The next logical set of algorithms to develop are addition, subtraction and digit shifting algorithms. These -algorithms make use of the lower level algorithms and are the cruicial building block for the multiplication algorithms. It is very important -that these algorithms are highly optimized. On their own they are simple $O(n)$ algorithms but they can be called from higher level algorithms -which easily places them at $O(n^2)$ or even $O(n^3)$ work levels. - -All nine algorithms within this chapter make use of the logical bit shift operations denoted by $<<$ and $>>$ for left and right -logical shifts respectively. A logical shift is analogous to sliding the decimal point of radix-10 representations. For example, the real -number $0.9345$ is equivalent to $93.45\%$ which is found by sliding the the decimal two places to the right (\textit{multiplying by $10^2$}). -Mathematically a logical shift is equivalent to a division or multiplication by a power of two. -For example, $a << k = a \cdot 2^k$ while $a >> k = \lfloor a/2^k \rfloor$. - -One significant difference between a logical shift and the way decimals are shifted is that digits below the zero'th position are removed -from the number. For example, consider $1101_2 >> 1$ using decimal notation this would produce $110.1_2$. However, with a logical shift the -result is $110_2$. - -\section{Addition and Subtraction} -In normal fixed precision arithmetic negative numbers are easily represented by subtraction from the modulus. For example, with 32-bit integers -$a - b\mbox{ (mod }2^{32}\mbox{)}$ is the same as $a + (2^{32} - b) \mbox{ (mod }2^{32}\mbox{)}$ since $2^{32} \equiv 0 \mbox{ (mod }2^{32}\mbox{)}$. -As a result subtraction can be performed with a trivial series of logical operations and an addition. - -However, in multiple precision arithmetic negative numbers are not represented in the same way. Instead a sign flag is used to keep track of the -sign of the integer. As a result signed addition and subtraction are actually implemented as conditional usage of lower level addition or -subtraction algorithms with the sign fixed up appropriately. - -The lower level algorithms will add or subtract integers without regard to the sign flag. That is they will add or subtract the magnitude of -the integers respectively. - -\subsection{Low Level Addition} -An unsigned addition of multiple precision integers is performed with the same long-hand algorithm used to add decimal numbers. That is to add the -trailing digits first and propagate the resulting carry upwards. Since this is a lower level algorithm the name will have a ``s\_'' prefix. -Historically that convention stems from the MPI library where ``s\_'' stood for static functions that were hidden from the developer entirely. - -\newpage -\begin{figure}[!here] -\begin{center} -\begin{small} -\begin{tabular}{l} -\hline Algorithm \textbf{s\_mp\_add}. \\ -\textbf{Input}. Two mp\_ints $a$ and $b$ \\ -\textbf{Output}. The unsigned addition $c = \vert a \vert + \vert b \vert$. \\ -\hline \\ -1. if $a.used > b.used$ then \\ -\hspace{+3mm}1.1 $min \leftarrow b.used$ \\ -\hspace{+3mm}1.2 $max \leftarrow a.used$ \\ -\hspace{+3mm}1.3 $x \leftarrow a$ \\ -2. else \\ -\hspace{+3mm}2.1 $min \leftarrow a.used$ \\ -\hspace{+3mm}2.2 $max \leftarrow b.used$ \\ -\hspace{+3mm}2.3 $x \leftarrow b$ \\ -3. If $c.alloc < max + 1$ then grow $c$ to hold at least $max + 1$ digits (\textit{mp\_grow}) \\ -4. If failed to grow $c$ return(\textit{MP\_MEM}) \\ -5. $oldused \leftarrow c.used$ \\ -6. $c.used \leftarrow max + 1$ \\ -7. $u \leftarrow 0$ \\ -8. for $n$ from $0$ to $min - 1$ do \\ -\hspace{+3mm}8.1 $c_n \leftarrow a_n + b_n + u$ \\ -\hspace{+3mm}8.2 $u \leftarrow c_n >> lg(\beta)$ \\ -\hspace{+3mm}8.3 $c_n \leftarrow c_n \mbox{ (mod }\beta\mbox{)}$ \\ -9. if $min \ne max$ then do \\ -\hspace{+3mm}9.1 for $n$ from $min$ to $max - 1$ do \\ -\hspace{+6mm}9.1.1 $c_n \leftarrow x_n + u$ \\ -\hspace{+6mm}9.1.2 $u \leftarrow c_n >> lg(\beta)$ \\ -\hspace{+6mm}9.1.3 $c_n \leftarrow c_n \mbox{ (mod }\beta\mbox{)}$ \\ -10. $c_{max} \leftarrow u$ \\ -11. if $olduse > max$ then \\ -\hspace{+3mm}11.1 for $n$ from $max + 1$ to $olduse - 1$ do \\ -\hspace{+6mm}11.1.1 $c_n \leftarrow 0$ \\ -12. Clamp excess digits in $c$. (\textit{mp\_clamp}) \\ -13. Return(\textit{MP\_OKAY}) \\ -\hline -\end{tabular} -\end{small} -\end{center} -\caption{Algorithm s\_mp\_add} -\end{figure} - -\textbf{Algorithm s\_mp\_add.} -This algorithm is loosely based on algorithm 14.7 of HAC \cite[pp. 594]{HAC} but has been extended to allow the inputs to have different magnitudes. -Coincidentally the description of algorithm A in Knuth \cite[pp. 266]{TAOCPV2} shares the same deficiency as the algorithm from \cite{HAC}. Even the -MIX pseudo machine code presented by Knuth \cite[pp. 266-267]{TAOCPV2} is incapable of handling inputs which are of different magnitudes. - -Steps 1 and 2 will sort the two inputs based on their \textbf{used} digit count. This allows the inputs to have varying magnitudes which not -only makes it more efficient than the trivial algorithm presented in the references but more flexible. The variable $min$ is given the lowest -digit count while $max$ is given the highest digit count. If both inputs have the same \textbf{used} digit count both $min$ and $max$ are -set to the same value. The variable $x$ is an \textit{alias} for the largest input and not meant to be a copy of it. After the inputs are sorted, -steps 3 and 4 will ensure that the destination $c$ can accommodate the result. The old \textbf{used} count from $c$ is copied to -$oldused$ so that excess digits can be cleared later, and the new \textbf{used} count is set to $max+1$, so that a carry from the most significant -word can be handled. - -At step 7 the carry variable $u$ is set to zero and the first part of the addition loop can begin. The first step of the loop (\textit{8.1}) adds -digits from the two inputs together along with the carry variable $u$. The following step extracts the carry bit by shifting the result of the -preceding step right by $lg(\beta)$ positions. The shift to extract the carry is similar to how carry extraction works with decimal addition. - -Consider adding $77$ to $65$, the first addition of the first column is $7 + 5$ which produces the result $12$. The trailing digit of the result -is $2 \equiv 12 \mbox{ (mod }10\mbox{)}$ and the carry is found by dividing (\textit{and ignoring the remainder}) $12$ by the radix or in this case $10$. The -division and multiplication of $10$ is simply a logical right or left shift, respectively, of the digits. In otherwords the carry can be extracted -by shifting one digit to the right. - -Note that $lg()$ is simply the base two logarithm such that $lg(2^k) = k$. This implies that $lg(\beta)$ is the number of bits in a radix-$\beta$ -digit. Therefore, a logical shift right of the summand by $lg(\beta)$ will extract the carry. The final step of the loop reduces the digit -modulo the radix $\beta$ to ensure it is in range. - -After step 8 the smallest input (\textit{or both if they are the same magnitude}) has been exhausted. Step 9 decides whether -the inputs were of equal magnitude. If not than another loop similar to that in step 8, must be executed. The loop at step -number 9.1 differs from the previous loop since it only adds the mp\_int $x$ along with the carry. - -Step 10 finishes the addition phase by copying the final carry to the highest location in the result $c_{max}$. Step 11 ensures that -leading digits that were originally present in $c$ are cleared. Finally excess leading digits are clamped and the algorithm returns success. - -\index{bn\_s\_mp\_add.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_s\_mp\_add.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* low level addition, based on HAC pp.594, Algorithm 14.7 */ -018 int -019 s_mp_add (mp_int * a, mp_int * b, mp_int * c) -020 \{ -021 mp_int *x; -022 int olduse, res, min, max; -023 -024 /* find sizes, we let |a| <= |b| which means we have to sort -025 * them. "x" will point to the input with the most digits -026 */ -027 if (a->used > b->used) \{ -028 min = b->used; -029 max = a->used; -030 x = a; -031 \} else \{ -032 min = a->used; -033 max = b->used; -034 x = b; -035 \} -036 -037 /* init result */ -038 if (c->alloc < max + 1) \{ -039 if ((res = mp_grow (c, max + 1)) != MP_OKAY) \{ -040 return res; -041 \} -042 \} -043 -044 /* get old used digit count and set new one */ -045 olduse = c->used; -046 c->used = max + 1; -047 -048 \{ -049 register mp_digit u, *tmpa, *tmpb, *tmpc; -050 register int i; -051 -052 /* alias for digit pointers */ -053 -054 /* first input */ -055 tmpa = a->dp; -056 -057 /* second input */ -058 tmpb = b->dp; -059 -060 /* destination */ -061 tmpc = c->dp; -062 -063 /* zero the carry */ -064 u = 0; -065 for (i = 0; i < min; i++) \{ -066 /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ -067 *tmpc = *tmpa++ + *tmpb++ + u; -068 -069 /* U = carry bit of T[i] */ -070 u = *tmpc >> ((mp_digit)DIGIT_BIT); -071 -072 /* take away carry bit from T[i] */ -073 *tmpc++ &= MP_MASK; -074 \} -075 -076 /* now copy higher words if any, that is in A+B -077 * if A or B has more digits add those in -078 */ -079 if (min != max) \{ -080 for (; i < max; i++) \{ -081 /* T[i] = X[i] + U */ -082 *tmpc = x->dp[i] + u; -083 -084 /* U = carry bit of T[i] */ -085 u = *tmpc >> ((mp_digit)DIGIT_BIT); -086 -087 /* take away carry bit from T[i] */ -088 *tmpc++ &= MP_MASK; -089 \} -090 \} -091 -092 /* add carry */ -093 *tmpc++ = u; -094 -095 /* clear digits above oldused */ -096 for (i = c->used; i < olduse; i++) \{ -097 *tmpc++ = 0; -098 \} -099 \} -100 -101 mp_clamp (c); -102 return MP_OKAY; -103 \} -\end{alltt} -\end{small} - -Lines 27 to 35 perform the initial sorting of the inputs and determine the $min$ and $max$ variables. Note that $x$ is a pointer to a -mp\_int assigned to the largest input, in effect it is a local alias. Lines 37 to 42 ensure that the destination is grown to -accomodate the result of the addition. - -Similar to the implementation of mp\_copy this function uses the braced code and local aliases coding style. The three aliases that are on -lines 55, 58 and 61 represent the two inputs and destination variables respectively. These aliases are used to ensure the -compiler does not have to dereference $a$, $b$ or $c$ (respectively) to access the digits of the respective mp\_int. - -The initial carry $u$ is cleared on line 64, note that $u$ is of type mp\_digit which ensures type compatibility within the -implementation. The initial addition loop begins on line 65 and ends on line 74. Similarly the conditional addition loop -begins on line 80 and ends on line 90. The addition is finished with the final carry being stored in $tmpc$ on line 93. -Note the ``++'' operator on the same line. After line 93 $tmpc$ will point to the $c.used$'th digit of the mp\_int $c$. This is useful -for the next loop on lines 96 to 99 which set any old upper digits to zero. - -\subsection{Low Level Subtraction} -The low level unsigned subtraction algorithm is very similar to the low level unsigned addition algorithm. The principle difference is that the -unsigned subtraction algorithm requires the result to be positive. That is when computing $a - b$ the condition $\vert a \vert \ge \vert b\vert$ must -be met for this algorithm to function properly. Keep in mind this low level algorithm is not meant to be used in higher level algorithms directly. -This algorithm as will be shown can be used to create functional signed addition and subtraction algorithms. - - -For this algorithm a new variable is required to make the description simpler. Recall from section 1.3.1 that a mp\_digit must be able to represent -the range $0 \le x < 2\beta$ for the algorithms to work correctly. However, it is allowable that a mp\_digit represent a larger range of values. For -this algorithm we will assume that the variable $\gamma$ represents the number of bits available in a -mp\_digit (\textit{this implies $2^{\gamma} > \beta$}). - -For example, the default for LibTomMath is to use a ``unsigned long'' for the mp\_digit ``type'' while $\beta = 2^{28}$. In ISO C an ``unsigned long'' -data type must be able to represent $0 \le x < 2^{32}$ meaning that in this case $\gamma = 32$. - -\newpage\begin{figure}[!here] -\begin{center} -\begin{small} -\begin{tabular}{l} -\hline Algorithm \textbf{s\_mp\_sub}. \\ -\textbf{Input}. Two mp\_ints $a$ and $b$ ($\vert a \vert \ge \vert b \vert$) \\ -\textbf{Output}. The unsigned subtraction $c = \vert a \vert - \vert b \vert$. \\ -\hline \\ -1. $min \leftarrow b.used$ \\ -2. $max \leftarrow a.used$ \\ -3. If $c.alloc < max$ then grow $c$ to hold at least $max$ digits. (\textit{mp\_grow}) \\ -4. If the reallocation failed return(\textit{MP\_MEM}). \\ -5. $oldused \leftarrow c.used$ \\ -6. $c.used \leftarrow max$ \\ -7. $u \leftarrow 0$ \\ -8. for $n$ from $0$ to $min - 1$ do \\ -\hspace{3mm}8.1 $c_n \leftarrow a_n - b_n - u$ \\ -\hspace{3mm}8.2 $u \leftarrow c_n >> (\gamma - 1)$ \\ -\hspace{3mm}8.3 $c_n \leftarrow c_n \mbox{ (mod }\beta\mbox{)}$ \\ -9. if $min < max$ then do \\ -\hspace{3mm}9.1 for $n$ from $min$ to $max - 1$ do \\ -\hspace{6mm}9.1.1 $c_n \leftarrow a_n - u$ \\ -\hspace{6mm}9.1.2 $u \leftarrow c_n >> (\gamma - 1)$ \\ -\hspace{6mm}9.1.3 $c_n \leftarrow c_n \mbox{ (mod }\beta\mbox{)}$ \\ -10. if $oldused > max$ then do \\ -\hspace{3mm}10.1 for $n$ from $max$ to $oldused - 1$ do \\ -\hspace{6mm}10.1.1 $c_n \leftarrow 0$ \\ -11. Clamp excess digits of $c$. (\textit{mp\_clamp}). \\ -12. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{small} -\end{center} -\caption{Algorithm s\_mp\_sub} -\end{figure} - -\textbf{Algorithm s\_mp\_sub.} -This algorithm performs the unsigned subtraction of two mp\_int variables under the restriction that the result must be positive. That is when -passing variables $a$ and $b$ the condition that $\vert a \vert \ge \vert b \vert$ must be met for the algorithm to function correctly. This -algorithm is loosely based on algorithm 14.9 \cite[pp. 595]{HAC} and is similar to algorithm S in \cite[pp. 267]{TAOCPV2} as well. As was the case -of the algorithm s\_mp\_add both other references lack discussion concerning various practical details such as when the inputs differ in magnitude. - -The initial sorting of the inputs is trivial in this algorithm since $a$ is guaranteed to have at least the same magnitude of $b$. Steps 1 and 2 -set the $min$ and $max$ variables. Unlike the addition routine there is guaranteed to be no carry which means that the final result can be at -most $max$ digits in length as opposed to $max + 1$. Similar to the addition algorithm the \textbf{used} count of $c$ is copied locally and -set to the maximal count for the operation. - -The subtraction loop that begins on step 8 is essentially the same as the addition loop of algorithm s\_mp\_add except single precision -subtraction is used instead. Note the use of the $\gamma$ variable to extract the carry (\textit{also known as the borrow}) within the subtraction -loops. Under the assumption that two's complement single precision arithmetic is used this will successfully extract the desired carry. - -For example, consider subtracting $0101_2$ from $0100_2$ where $\gamma = 4$ and $\beta = 2$. The least significant bit will force a carry upwards to -the third bit which will be set to zero after the borrow. After the very first bit has been subtracted $4 - 1 \equiv 0011_2$ will remain, When the -third bit of $0101_2$ is subtracted from the result it will cause another carry. In this case though the carry will be forced to propagate all the -way to the most significant bit. - -Recall that $\beta < 2^{\gamma}$. This means that if a carry does occur just before the $lg(\beta)$'th bit it will propagate all the way to the most -significant bit. Thus, the high order bits of the mp\_digit that are not part of the actual digit will either be all zero, or all one. All that -is needed is a single zero or one bit for the carry. Therefore a single logical shift right by $\gamma - 1$ positions is sufficient to extract the -carry. This method of carry extraction may seem awkward but the reason for it becomes apparent when the implementation is discussed. - -If $b$ has a smaller magnitude than $a$ then step 9 will force the carry and copy operation to propagate through the larger input $a$ into $c$. Step -10 will ensure that any leading digits of $c$ above the $max$'th position are zeroed. - -\index{bn\_s\_mp\_sub.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_s\_mp\_sub.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ -018 int -019 s_mp_sub (mp_int * a, mp_int * b, mp_int * c) -020 \{ -021 int olduse, res, min, max; -022 -023 /* find sizes */ -024 min = b->used; -025 max = a->used; -026 -027 /* init result */ -028 if (c->alloc < max) \{ -029 if ((res = mp_grow (c, max)) != MP_OKAY) \{ -030 return res; -031 \} -032 \} -033 olduse = c->used; -034 c->used = max; -035 -036 \{ -037 register mp_digit u, *tmpa, *tmpb, *tmpc; -038 register int i; -039 -040 /* alias for digit pointers */ -041 tmpa = a->dp; -042 tmpb = b->dp; -043 tmpc = c->dp; -044 -045 /* set carry to zero */ -046 u = 0; -047 for (i = 0; i < min; i++) \{ -048 /* T[i] = A[i] - B[i] - U */ -049 *tmpc = *tmpa++ - *tmpb++ - u; -050 -051 /* U = carry bit of T[i] -052 * Note this saves performing an AND operation since -053 * if a carry does occur it will propagate all the way to the -054 * MSB. As a result a single shift is enough to get the carry -055 */ -056 u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); -057 -058 /* Clear carry from T[i] */ -059 *tmpc++ &= MP_MASK; -060 \} -061 -062 /* now copy higher words if any, e.g. if A has more digits than B */ -063 for (; i < max; i++) \{ -064 /* T[i] = A[i] - U */ -065 *tmpc = *tmpa++ - u; -066 -067 /* U = carry bit of T[i] */ -068 u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); -069 -070 /* Clear carry from T[i] */ -071 *tmpc++ &= MP_MASK; -072 \} -073 -074 /* clear digits above used (since we may not have grown result above) */ - -075 for (i = c->used; i < olduse; i++) \{ -076 *tmpc++ = 0; -077 \} -078 \} -079 -080 mp_clamp (c); -081 return MP_OKAY; -082 \} -083 -\end{alltt} -\end{small} - -Line 24 and 25 perform the initial hardcoded sorting of the inputs. In reality the $min$ and $max$ variables are only aliases and are only -used to make the source code easier to read. Again the pointer alias optimization is used within this algorithm. Lines 41, 42 and 43 initialize the aliases for -$a$, $b$ and $c$ respectively. - -The first subtraction loop occurs on lines 46 through 60. The theory behind the subtraction loop is exactly the same as that for -the addition loop. As remarked earlier there is an implementation reason for using the ``awkward'' method of extracting the carry -(\textit{see line 56}). The traditional method for extracting the carry would be to shift by $lg(\beta)$ positions and logically AND -the least significant bit. The AND operation is required because all of the bits above the $\lg(\beta)$'th bit will be set to one after a carry -occurs from subtraction. This carry extraction requires two relatively cheap operations to extract the carry. The other method is to simply -shift the most significant bit to the least significant bit thus extracting the carry with a single cheap operation. This optimization only works on -twos compliment machines which is a safe assumption to make. - -If $a$ has a larger magnitude than $b$ an additional loop (\textit{see lines 63 through 72}) is required to propagate the carry through -$a$ and copy the result to $c$. - -\subsection{High Level Addition} -Now that both lower level addition and subtraction algorithms have been established an effective high level signed addition algorithm can be -established. This high level addition algorithm will be what other algorithms and developers will use to perform addition of mp\_int data -types. - -Recall from section 5.2 that an mp\_int represents an integer with an unsigned mantissa (\textit{the array of digits}) and a \textbf{sign} -flag. A high level addition is actually performed as a series of eight separate cases which can be optimized down to three unique cases. - -\begin{figure}[!here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_add}. \\ -\textbf{Input}. Two mp\_ints $a$ and $b$ \\ -\textbf{Output}. The signed addition $c = a + b$. \\ -\hline \\ -1. if $a.sign = b.sign$ then do \\ -\hspace{3mm}1.1 $c.sign \leftarrow a.sign$ \\ -\hspace{3mm}1.2 $c \leftarrow \vert a \vert + \vert b \vert$ (\textit{s\_mp\_add})\\ -2. else do \\ -\hspace{3mm}2.1 if $\vert a \vert < \vert b \vert$ then do (\textit{mp\_cmp\_mag}) \\ -\hspace{6mm}2.1.1 $c.sign \leftarrow b.sign$ \\ -\hspace{6mm}2.1.2 $c \leftarrow \vert b \vert - \vert a \vert$ (\textit{s\_mp\_sub}) \\ -\hspace{3mm}2.2 else do \\ -\hspace{6mm}2.2.1 $c.sign \leftarrow a.sign$ \\ -\hspace{6mm}2.2.2 $c \leftarrow \vert a \vert - \vert b \vert$ \\ -3. If any of the lower level operations failed return(\textit{MP\_MEM}) \\ -4. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_add} -\end{figure} - -\textbf{Algorithm mp\_add.} -This algorithm performs the signed addition of two mp\_int variables. There is no reference algorithm to draw upon from either \cite{TAOCPV2} or -\cite{HAC} since they both only provide unsigned operations. The algorithm is fairly straightforward but restricted since subtraction can only -produce positive results. - -\begin{figure}[here] -\begin{small} -\begin{center} -\begin{tabular}{|c|c|c|c|c|} -\hline \textbf{Sign of $a$} & \textbf{Sign of $b$} & \textbf{$\vert a \vert > \vert b \vert $} & \textbf{Unsigned Operation} & \textbf{Result Sign Flag} \\ -\hline $+$ & $+$ & Yes & $c = a + b$ & $a.sign$ \\ -\hline $+$ & $+$ & No & $c = a + b$ & $a.sign$ \\ -\hline $-$ & $-$ & Yes & $c = a + b$ & $a.sign$ \\ -\hline $-$ & $-$ & No & $c = a + b$ & $a.sign$ \\ -\hline &&&&\\ - -\hline $+$ & $-$ & No & $c = b - a$ & $b.sign$ \\ -\hline $-$ & $+$ & No & $c = b - a$ & $b.sign$ \\ - -\hline &&&&\\ - -\hline $+$ & $-$ & Yes & $c = a - b$ & $a.sign$ \\ -\hline $-$ & $+$ & Yes & $c = a - b$ & $a.sign$ \\ - -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Addition Guide Chart} -\label{fig:AddChart} -\end{figure} - -Figure~\ref{fig:AddChart} lists all of the eight possible input combinations and is sorted to show that only three specific cases need to be handled. The -return code of the unsigned operations at step 1.2, 2.1.2 and 2.2.2 are forwarded to step 3 to check for errors. This simplifies the description -of the algorithm considerably and best follows how the implementation actually was achieved. - -Also note how the \textbf{sign} is set before the unsigned addition or subtraction is performed. Recall from the descriptions of algorithms -s\_mp\_add and s\_mp\_sub that the mp\_clamp function is used at the end to trim excess digits. The mp\_clamp algorithm will set the \textbf{sign} -to \textbf{MP\_ZPOS} when the \textbf{used} digit count reaches zero. - -For example, consider performing $-a + a$ with algorithm mp\_add. By the description of the algorithm the sign is set to \textbf{MP\_NEG} which would -produce a result of $-0$. However, since the sign is set first then the unsigned addition is performed the subsequent usage of algorithm mp\_clamp -within algorithm s\_mp\_add will force $-0$ to become $0$. - -\index{bn\_mp\_add.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_add.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* high level addition (handles signs) */ -018 int -019 mp_add (mp_int * a, mp_int * b, mp_int * c) -020 \{ -021 int sa, sb, res; -022 -023 /* get sign of both inputs */ -024 sa = a->sign; -025 sb = b->sign; -026 -027 /* handle two cases, not four */ -028 if (sa == sb) \{ -029 /* both positive or both negative */ -030 /* add their magnitudes, copy the sign */ -031 c->sign = sa; -032 res = s_mp_add (a, b, c); -033 \} else \{ -034 /* one positive, the other negative */ -035 /* subtract the one with the greater magnitude from */ -036 /* the one of the lesser magnitude. The result gets */ -037 /* the sign of the one with the greater magnitude. */ -038 if (mp_cmp_mag (a, b) == MP_LT) \{ -039 c->sign = sb; -040 res = s_mp_sub (b, a, c); -041 \} else \{ -042 c->sign = sa; -043 res = s_mp_sub (a, b, c); -044 \} -045 \} -046 return res; -047 \} -048 -\end{alltt} -\end{small} - -The source code follows the algorithm fairly closely. The most notable new source code addition is the usage of the $res$ integer variable which -is used to pass result of the unsigned operations forward. Unlike in the algorithm, the variable $res$ is merely returned as is without -explicitly checking it and returning the constant \textbf{MP\_OKAY}. The observation is this algorithm will succeed or fail only if the lower -level functions do so. Returning their return code is sufficient. - -\subsection{High Level Subtraction} -The high level signed subtraction algorithm is essentially the same as the high level signed addition algorithm. - -\newpage\begin{figure}[!here] -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_sub}. \\ -\textbf{Input}. Two mp\_ints $a$ and $b$ \\ -\textbf{Output}. The signed subtraction $c = a - b$. \\ -\hline \\ -1. if $a.sign \ne b.sign$ then do \\ -\hspace{3mm}1.1 $c.sign \leftarrow a.sign$ \\ -\hspace{3mm}1.2 $c \leftarrow \vert a \vert + \vert b \vert$ (\textit{s\_mp\_add}) \\ -2. else do \\ -\hspace{3mm}2.1 if $\vert a \vert \ge \vert b \vert$ then do (\textit{mp\_cmp\_mag}) \\ -\hspace{6mm}2.1.1 $c.sign \leftarrow a.sign$ \\ -\hspace{6mm}2.1.2 $c \leftarrow \vert a \vert - \vert b \vert$ (\textit{s\_mp\_sub}) \\ -\hspace{3mm}2.2 else do \\ -\hspace{6mm}2.2.1 $c.sign \leftarrow \left \lbrace \begin{array}{ll} - MP\_ZPOS & \mbox{if }a.sign = MP\_NEG \\ - MP\_NEG & \mbox{otherwise} \\ - \end{array} \right .$ \\ -\hspace{6mm}2.2.2 $c \leftarrow \vert b \vert - \vert a \vert$ \\ -3. If any of the lower level operations failed return(\textit{MP\_MEM}). \\ -4. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\caption{Algorithm mp\_sub} -\end{figure} - -\textbf{Algorithm mp\_sub.} -This algorithm performs the signed subtraction of two inputs. Similar to algorithm mp\_add there is no reference in either \cite{TAOCPV2} or -\cite{HAC}. Also this algorithm is restricted by algorithm s\_mp\_sub. The following chart lists the eight possible inputs and -the operations required. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{|c|c|c|c|c|} -\hline \textbf{Sign of $a$} & \textbf{Sign of $b$} & \textbf{$\vert a \vert \ge \vert b \vert $} & \textbf{Unsigned Operation} & \textbf{Result Sign Flag} \\ -\hline $+$ & $-$ & Yes & $c = a + b$ & $a.sign$ \\ -\hline $+$ & $-$ & No & $c = a + b$ & $a.sign$ \\ -\hline $-$ & $+$ & Yes & $c = a + b$ & $a.sign$ \\ -\hline $-$ & $+$ & No & $c = a + b$ & $a.sign$ \\ -\hline &&&& \\ -\hline $+$ & $+$ & Yes & $c = a - b$ & $a.sign$ \\ -\hline $-$ & $-$ & Yes & $c = a - b$ & $a.sign$ \\ -\hline &&&& \\ -\hline $+$ & $+$ & No & $c = b - a$ & $\mbox{opposite of }a.sign$ \\ -\hline $-$ & $-$ & No & $c = b - a$ & $\mbox{opposite of }a.sign$ \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Subtraction Guide Chart} -\end{figure} - -Similar to the case of algorithm mp\_add the \textbf{sign} is set first before the unsigned addition or subtraction. That is to prevent the -algorithm from producing $-a - -a = -0$ as a result. - -\index{bn\_mp\_sub.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_sub.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* high level subtraction (handles signs) */ -018 int -019 mp_sub (mp_int * a, mp_int * b, mp_int * c) -020 \{ -021 int sa, sb, res; -022 -023 sa = a->sign; -024 sb = b->sign; -025 -026 if (sa != sb) \{ -027 /* subtract a negative from a positive, OR */ -028 /* subtract a positive from a negative. */ -029 /* In either case, ADD their magnitudes, */ -030 /* and use the sign of the first number. */ -031 c->sign = sa; -032 res = s_mp_add (a, b, c); -033 \} else \{ -034 /* subtract a positive from a positive, OR */ -035 /* subtract a negative from a negative. */ -036 /* First, take the difference between their */ -037 /* magnitudes, then... */ -038 if (mp_cmp_mag (a, b) != MP_LT) \{ -039 /* Copy the sign from the first */ -040 c->sign = sa; -041 /* The first has a larger or equal magnitude */ -042 res = s_mp_sub (a, b, c); -043 \} else \{ -044 /* The result has the *opposite* sign from */ -045 /* the first number. */ -046 c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS; -047 /* The second has a larger magnitude */ -048 res = s_mp_sub (b, a, c); -049 \} -050 \} -051 return res; -052 \} -053 -\end{alltt} -\end{small} - -Much like the implementation of algorithm mp\_add the variable $res$ is used to catch the return code of the unsigned addition or subtraction operations -and forward it to the end of the function. On line 38 the ``not equal to'' \textbf{MP\_LT} expression is used to emulate a -``greater than or equal to'' comparison. - -\section{Bit and Digit Shifting} -It is quite common to think of a multiple precision integer as a polynomial in $x$, that is $y = f(\beta)$ where $f(x) = \sum_{i=0}^{n-1} a_i x^i$. -This notation arises within discussion of Montgomery and Diminished Radix Reduction as well as Karatsuba multiplication and squaring. - -In order to facilitate operations on polynomials in $x$ as above a series of simple ``digit'' algorithms have to be established. That is to shift -the digits left or right as well to shift individual bits of the digits left and right. It is important to note that not all ``shift'' operations -are on radix-$\beta$ digits. - -\subsection{Multiplication by Two} - -In a binary system where the radix is a power of two multiplication by two not only arises often in other algorithms it is a fairly efficient -operation to perform. A single precision logical shift left is sufficient to multiply a single digit by two. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_mul\_2}. \\ -\textbf{Input}. One mp\_int $a$ \\ -\textbf{Output}. $b = 2a$. \\ -\hline \\ -1. If $b.alloc < a.used + 1$ then grow $b$ to hold $a.used + 1$ digits. (\textit{mp\_grow}) \\ -2. If the reallocation failed return(\textit{MP\_MEM}). \\ -3. $oldused \leftarrow b.used$ \\ -4. $b.used \leftarrow a.used$ \\ -5. $r \leftarrow 0$ \\ -6. for $n$ from 0 to $a.used - 1$ do \\ -\hspace{3mm}6.1 $rr \leftarrow a_n >> (lg(\beta) - 1)$ \\ -\hspace{3mm}6.2 $b_n \leftarrow (a_n << 1) + r \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{3mm}6.3 $r \leftarrow rr$ \\ -7. If $r \ne 0$ then do \\ -\hspace{3mm}7.1 $b_{n + 1} \leftarrow r$ \\ -\hspace{3mm}7.2 $b.used \leftarrow b.used + 1$ \\ -8. If $b.used < oldused - 1$ then do \\ -\hspace{3mm}8.1 for $n$ from $b.used$ to $oldused - 1$ do \\ -\hspace{6mm}8.1.1 $b_n \leftarrow 0$ \\ -9. $b.sign \leftarrow a.sign$ \\ -10. Return(\textit{MP\_OKAY}).\\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_mul\_2} -\end{figure} - -\textbf{Algorithm mp\_mul\_2.} -This algorithm will quickly multiply a mp\_int by two provided $\beta$ is a power of two. Neither \cite{TAOCPV2} nor \cite{HAC} describe such -an algorithm despite the fact it arises often in other algorithms. The algorithm is setup much like the lower level algorithm s\_mp\_add since -it is for all intents and purposes equivalent to the operation $b = \vert a \vert + \vert a \vert$. - -Step 1 and 2 grow the input as required to accomodate the maximum number of \textbf{used} digits in the result. The initial \textbf{used} count -is set to $a.used$ at step 4. Only if there is a final carry will the \textbf{used} count require adjustment. - -Step 6 is an optimization implementation of the addition loop for this specific case. That is since the two values being added together -are the same there is no need to perform two reads from the digits of $a$. Step 6.1 performs a single precision shift on the current digit $a_n$ to -obtain what will be the carry for the next iteration. Step 6.2 calculates the $n$'th digit of the result as single precision shift of $a_n$ plus -the previous carry. Recall from section 5.1 that $a_n << 1$ is equivalent to $a_n \cdot 2$. An iteration of the addition loop is finished with -forwarding the carry to the next iteration. - -Step 7 takes care of any final carry by setting the $a.used$'th digit of the result to the carry and augmenting the \textbf{used} count of $b$. -Step 8 clears any leading digits of $b$ in case it originally had a larger magnitude than $a$. - -\index{bn\_mp\_mul\_2.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_mul\_2.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* b = a*2 */ -018 int -019 mp_mul_2 (mp_int * a, mp_int * b) -020 \{ -021 int x, res, oldused; -022 -023 /* grow to accomodate result */ -024 if (b->alloc < a->used + 1) \{ -025 if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) \{ -026 return res; -027 \} -028 \} -029 -030 oldused = b->used; -031 b->used = a->used; -032 -033 \{ -034 register mp_digit r, rr, *tmpa, *tmpb; -035 -036 /* alias for source */ -037 tmpa = a->dp; -038 -039 /* alias for dest */ -040 tmpb = b->dp; -041 -042 /* carry */ -043 r = 0; -044 for (x = 0; x < a->used; x++) \{ -045 -046 /* get what will be the *next* carry bit from the -047 * MSB of the current digit -048 */ -049 rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1)); -050 -051 /* now shift up this digit, add in the carry [from the previous] */ -052 *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK; -053 -054 /* copy the carry that would be from the source -055 * digit into the next iteration -056 */ -057 r = rr; -058 \} -059 -060 /* new leading digit? */ -061 if (r != 0) \{ -062 /* add a MSB which is always 1 at this point */ -063 *tmpb = 1; -064 ++b->used; -065 \} -066 -067 /* now zero any excess digits on the destination -068 * that we didn't write to -069 */ -070 tmpb = b->dp + b->used; -071 for (x = b->used; x < oldused; x++) \{ -072 *tmpb++ = 0; -073 \} -074 \} -075 b->sign = a->sign; -076 return MP_OKAY; -077 \} -\end{alltt} -\end{small} - -This implementation is essentially an optimized implementation of s\_mp\_add for the case of doubling an input. The only noteworthy difference -is the use of the logical shift operator on line 52 to perform a single precision doubling. - -\subsection{Division by Two} -A division by two can just as easily be accomplished with a logical shift right as multiplication by two can be with a logical shift left. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_div\_2}. \\ -\textbf{Input}. One mp\_int $a$ \\ -\textbf{Output}. $b = a/2$. \\ -\hline \\ -1. If $b.alloc < a.used$ then grow $b$ to hold $a.used$ digits. (\textit{mp\_grow}) \\ -2. If the reallocation failed return(\textit{MP\_MEM}). \\ -3. $oldused \leftarrow b.used$ \\ -4. $b.used \leftarrow a.used$ \\ -5. $r \leftarrow 0$ \\ -6. for $n$ from $b.used - 1$ to $0$ do \\ -\hspace{3mm}6.1 $rr \leftarrow a_n \mbox{ (mod }2\mbox{)}$\\ -\hspace{3mm}6.2 $b_n \leftarrow (a_n >> 1) + (r << (lg(\beta) - 1)) \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{3mm}6.3 $r \leftarrow rr$ \\ -7. If $b.used < oldused - 1$ then do \\ -\hspace{3mm}7.1 for $n$ from $b.used$ to $oldused - 1$ do \\ -\hspace{6mm}7.1.1 $b_n \leftarrow 0$ \\ -8. $b.sign \leftarrow a.sign$ \\ -9. Clamp excess digits of $b$. (\textit{mp\_clamp}) \\ -10. Return(\textit{MP\_OKAY}).\\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_div\_2} -\end{figure} - -\textbf{Algorithm mp\_div\_2.} -This algorithm will divide an mp\_int by two using logical shifts to the right. Like mp\_mul\_2 it uses a modified low level addition -core as the basis of the algorithm. Unlike mp\_mul\_2 the shift operations work from the leading digit to the trailing digit. The algorithm -could be written to work from the trailing digit to the leading digit however, it would have to stop one short of $a.used - 1$ digits to prevent -reading past the end of the array of digits. - -Essentially the loop at step 6 is similar to that of mp\_mul\_2 except the logical shifts go in the opposite direction and the carry is at the -least significant bit not the most significant bit. - -\index{bn\_mp\_div\_2.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_div\_2.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* b = a/2 */ -018 int -019 mp_div_2 (mp_int * a, mp_int * b) -020 \{ -021 int x, res, oldused; -022 -023 /* copy */ -024 if (b->alloc < a->used) \{ -025 if ((res = mp_grow (b, a->used)) != MP_OKAY) \{ -026 return res; -027 \} -028 \} -029 -030 oldused = b->used; -031 b->used = a->used; -032 \{ -033 register mp_digit r, rr, *tmpa, *tmpb; -034 -035 /* source alias */ -036 tmpa = a->dp + b->used - 1; -037 -038 /* dest alias */ -039 tmpb = b->dp + b->used - 1; -040 -041 /* carry */ -042 r = 0; -043 for (x = b->used - 1; x >= 0; x--) \{ -044 /* get the carry for the next iteration */ -045 rr = *tmpa & 1; -046 -047 /* shift the current digit, add in carry and store */ -048 *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1)); -049 -050 /* forward carry to next iteration */ -051 r = rr; -052 \} -053 -054 /* zero excess digits */ -055 tmpb = b->dp + b->used; -056 for (x = b->used; x < oldused; x++) \{ -057 *tmpb++ = 0; -058 \} -059 \} -060 b->sign = a->sign; -061 mp_clamp (b); -062 return MP_OKAY; -063 \} -\end{alltt} -\end{small} - -\section{Polynomial Basis Operations} -Recall from section 5.3 that any integer can be represented as a polynomial in $x$ as $y = f(\beta)$. Such a representation is also known as -the polynomial basis \cite[pp. 48]{ROSE}. Given such a notation a multiplication or division by $x$ amounts to shifting whole digits a single -place. The need for such operations arises in several other higher level algorithms such as Barrett and Montgomery reduction, integer -division and Karatsuba multiplication. - -Converting from an array of digits to polynomial basis is very simple. Consider the integer $y \equiv (a_2, a_1, a_0)_{\beta}$ and recall that -$y = \sum_{i=0}^{2} a_i \beta^i$. Simply replace $\beta$ with $x$ and the expression is in polynomial basis. For example, $f(x) = 8x + 9$ is the -polynomial basis representation for $89$ using radix ten. That is, $f(10) = 8(10) + 9 = 89$. - -\subsection{Multiplication by $x$} - -Given a polynomial in $x$ such as $f(x) = a_n x^n + a_{n-1} x^{n-1} + ... + a_0$ multiplying by $x$ amounts to shifting the coefficients up one -degree. In this case $f(x) \cdot x = a_n x^{n+1} + a_{n-1} x^n + ... + a_0 x$. From a scalar basis point of view multiplying by $x$ is equivalent to -multiplying by the integer $\beta$. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_lshd}. \\ -\textbf{Input}. One mp\_int $a$ and an integer $b$ \\ -\textbf{Output}. $a \leftarrow a \cdot \beta^b$ (equivalent to multiplication by $x^b$). \\ -\hline \\ -1. If $b \le 0$ then return(\textit{MP\_OKAY}). \\ -2. If $a.alloc < a.used + b$ then grow $a$ to at least $a.used + b$ digits. (\textit{mp\_grow}). \\ -3. If the reallocation failed return(\textit{MP\_MEM}). \\ -4. $a.used \leftarrow a.used + b$ \\ -5. $i \leftarrow a.used - 1$ \\ -6. $j \leftarrow a.used - 1 - b$ \\ -7. for $n$ from $a.used - 1$ to $b$ do \\ -\hspace{3mm}7.1 $a_{i} \leftarrow a_{j}$ \\ -\hspace{3mm}7.2 $i \leftarrow i - 1$ \\ -\hspace{3mm}7.3 $j \leftarrow j - 1$ \\ -8. for $n$ from 0 to $b - 1$ do \\ -\hspace{3mm}8.1 $a_n \leftarrow 0$ \\ -9. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_lshd} -\end{figure} - -\textbf{Algorithm mp\_lshd.} -This algorithm multiplies an mp\_int by the $b$'th power of $x$. This is equivalent to multiplying by $\beta^b$. The algorithm differs -from the other algorithms presented so far as it performs the operation in place instead storing the result in a separate location. The -motivation behind this change is due to the way this function is typically used. Algorithms such as mp\_add store the result in an optionally -different third mp\_int because the original inputs are often still required. Algorithm mp\_lshd (\textit{and similarly algorithm mp\_rshd}) is -typically used on values where the original value is no longer required. The algorithm will return success immediately if -$b \le 0$ since the rest of algorithm is only valid when $b > 0$. - -First the destination $a$ is grown as required to accomodate the result. The counters $i$ and $j$ are used to form a \textit{sliding window} over -the digits of $a$ of length $b$. The head of the sliding window is at $i$ (\textit{the leading digit}) and the tail at $j$ (\textit{the trailing digit}). -The loop on step 7 copies the digit from the tail to the head. In each iteration the window is moved down one digit. The last loop on -step 8 sets the lower $b$ digits to zero. - -\newpage -\begin{center} -\begin{figure}[here] -\includegraphics{pics/sliding_window} -\caption{Sliding Window Movement} -\end{figure} -\end{center} - -\index{bn\_mp\_lshd.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_lshd.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* shift left a certain amount of digits */ -018 int -019 mp_lshd (mp_int * a, int b) -020 \{ -021 int x, res; -022 -023 /* if its less than zero return */ -024 if (b <= 0) \{ -025 return MP_OKAY; -026 \} -027 -028 /* grow to fit the new digits */ -029 if (a->alloc < a->used + b) \{ -030 if ((res = mp_grow (a, a->used + b)) != MP_OKAY) \{ -031 return res; -032 \} -033 \} -034 -035 \{ -036 register mp_digit *top, *bottom; -037 -038 /* increment the used by the shift amount then copy upwards */ -039 a->used += b; -040 -041 /* top */ -042 top = a->dp + a->used - 1; -043 -044 /* base */ -045 bottom = a->dp + a->used - 1 - b; -046 -047 /* much like mp_rshd this is implemented using a sliding window -048 * except the window goes the otherway around. Copying from -049 * the bottom to the top. see bn_mp_rshd.c for more info. -050 */ -051 for (x = a->used - 1; x >= b; x--) \{ -052 *top-- = *bottom--; -053 \} -054 -055 /* zero the lower digits */ -056 top = a->dp; -057 for (x = 0; x < b; x++) \{ -058 *top++ = 0; -059 \} -060 \} -061 return MP_OKAY; -062 \} -\end{alltt} -\end{small} - -The if statement on line 24 ensures that the $b$ variable is greater than zero. The \textbf{used} count is incremented by $b$ before -the copy loop begins. This elminates the need for an additional variable in the for loop. The variable $top$ on line 42 is an alias -for the leading digit while $bottom$ on line 45 is an alias for the trailing edge. The aliases form a window of exactly $b$ digits -over the input. - -\subsection{Division by $x$} - -Division by powers of $x$ is easily achieved by shifting the digits right and removing any that will end up to the right of the zero'th digit. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_rshd}. \\ -\textbf{Input}. One mp\_int $a$ and an integer $b$ \\ -\textbf{Output}. $a \leftarrow a / \beta^b$ (Divide by $x^b$). \\ -\hline \\ -1. If $b \le 0$ then return. \\ -2. If $a.used \le b$ then do \\ -\hspace{3mm}2.1 Zero $a$. (\textit{mp\_zero}). \\ -\hspace{3mm}2.2 Return. \\ -3. $i \leftarrow 0$ \\ -4. $j \leftarrow b$ \\ -5. for $n$ from 0 to $a.used - b - 1$ do \\ -\hspace{3mm}5.1 $a_i \leftarrow a_j$ \\ -\hspace{3mm}5.2 $i \leftarrow i + 1$ \\ -\hspace{3mm}5.3 $j \leftarrow j + 1$ \\ -6. for $n$ from $a.used - b$ to $a.used - 1$ do \\ -\hspace{3mm}6.1 $a_n \leftarrow 0$ \\ -7. $a.used \leftarrow a.used - b$ \\ -8. Return. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_rshd} -\end{figure} - -\textbf{Algorithm mp\_rshd.} -This algorithm divides the input in place by the $b$'th power of $x$. It is analogous to dividing by a $\beta^b$ but much quicker since -it does not require single precision division. This algorithm does not actually return an error code as it cannot fail. - -If the input $b$ is less than one the algorithm quickly returns without performing any work. If the \textbf{used} count is less than or equal -to the shift count $b$ then it will simply zero the input and return. - -After the trivial cases of inputs have been handled the sliding window is setup. Much like the case of algorithm mp\_lshd a sliding window that -is $b$ digits wide is used to copy the digits. Unlike mp\_lshd the window slides in the opposite direction from the trailing to the leading digit. -Also the digits are copied from the leading to the trailing edge. - -Once the window copy is complete the upper digits must be zeroed and the \textbf{used} count decremented. - -\index{bn\_mp\_rshd.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_rshd.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* shift right a certain amount of digits */ -018 void -019 mp_rshd (mp_int * a, int b) -020 \{ -021 int x; -022 -023 /* if b <= 0 then ignore it */ -024 if (b <= 0) \{ -025 return; -026 \} -027 -028 /* if b > used then simply zero it and return */ -029 if (a->used <= b) \{ -030 mp_zero (a); -031 return; -032 \} -033 -034 \{ -035 register mp_digit *bottom, *top; -036 -037 /* shift the digits down */ -038 -039 /* bottom */ -040 bottom = a->dp; -041 -042 /* top [offset into digits] */ -043 top = a->dp + b; -044 -045 /* this is implemented as a sliding window where -046 * the window is b-digits long and digits from -047 * the top of the window are copied to the bottom -048 * -049 * e.g. -050 -051 b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> -052 /\symbol{92} | ----> -053 \symbol{92}-------------------/ ----> -054 */ -055 for (x = 0; x < (a->used - b); x++) \{ -056 *bottom++ = *top++; -057 \} -058 -059 /* zero the top digits */ -060 for (; x < a->used; x++) \{ -061 *bottom++ = 0; -062 \} -063 \} -064 -065 /* remove excess digits */ -066 a->used -= b; -067 \} -\end{alltt} -\end{small} - -The only noteworthy element of this routine is the lack of a return type. - --- Will update later to give it a return type...Tom - -\section{Powers of Two} - -Now that algorithms for moving single bits as well as whole digits exist algorithms for moving the ``in between'' distances are required. For -example, to quickly multiply by $2^k$ for any $k$ without using a full multiplier algorithm would prove useful. Instead of performing single -shifts $k$ times to achieve a multiplication by $2^{\pm k}$ a mixture of whole digit shifting and partial digit shifting is employed. - -\subsection{Multiplication by Power of Two} - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_mul\_2d}. \\ -\textbf{Input}. One mp\_int $a$ and an integer $b$ \\ -\textbf{Output}. $c \leftarrow a \cdot 2^b$. \\ -\hline \\ -1. $c \leftarrow a$. (\textit{mp\_copy}) \\ -2. If $c.alloc < c.used + \lfloor b / lg(\beta) \rfloor + 2$ then grow $c$ accordingly. \\ -3. If the reallocation failed return(\textit{MP\_MEM}). \\ -4. If $b \ge lg(\beta)$ then \\ -\hspace{3mm}4.1 $c \leftarrow c \cdot \beta^{\lfloor b / lg(\beta) \rfloor}$ (\textit{mp\_lshd}). \\ -\hspace{3mm}4.2 If step 4.1 failed return(\textit{MP\_MEM}). \\ -5. $d \leftarrow b \mbox{ (mod }lg(\beta)\mbox{)}$ \\ -6. If $d \ne 0$ then do \\ -\hspace{3mm}6.1 $mask \leftarrow 2^d$ \\ -\hspace{3mm}6.2 $r \leftarrow 0$ \\ -\hspace{3mm}6.3 for $n$ from $0$ to $c.used - 1$ do \\ -\hspace{6mm}6.3.1 $rr \leftarrow c_n >> (lg(\beta) - d) \mbox{ (mod }mask\mbox{)}$ \\ -\hspace{6mm}6.3.2 $c_n \leftarrow (c_n << d) + r \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{6mm}6.3.3 $r \leftarrow rr$ \\ -\hspace{3mm}6.4 If $r > 0$ then do \\ -\hspace{6mm}6.4.1 $c_{c.used} \leftarrow r$ \\ -\hspace{6mm}6.4.2 $c.used \leftarrow c.used + 1$ \\ -7. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_mul\_2d} -\end{figure} - -\textbf{Algorithm mp\_mul\_2d.} -This algorithm multiplies $a$ by $2^b$ and stores the result in $c$. The algorithm uses algorithm mp\_lshd and a derivative of algorithm mp\_mul\_2 to -quickly compute the product. - -First the algorithm will multiply $a$ by $x^{\lfloor b / lg(\beta) \rfloor}$ which will ensure that the remainder multiplicand is less than -$\beta$. For example, if $b = 37$ and $\beta = 2^{28}$ then this step will multiply by $x$ leaving a multiplication by $2^{37 - 28} = 2^{9}$ -left. - -After the digits have been shifted appropriately at most $lg(\beta) - 1$ shifts are left to perform. Step 5 calculates the number of remaining shifts -required. If it is non-zero a modified shift loop is used to calculate the remaining product. -Essentially the loop is a generic version of algorith mp\_mul2 designed to handle any shift count in the range $1 \le x < lg(\beta)$. The $mask$ -variable is used to extract the upper $d$ bits to form the carry for the next iteration. - -This algorithm is loosely measured as a $O(2n)$ algorithm which means that if the input is $n$-digits that it takes $2n$ ``time'' to -complete. It is possible to optimize this algorithm down to a $O(n)$ algorithm at a cost of making the algorithm slightly harder to follow. - -\index{bn\_mp\_mul\_2d.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_mul\_2d.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* NOTE: This routine requires updating. For instance the c->used = c->all - oc bit -018 is wrong. We should just shift c->used digits then set the carry as c->d - p[c->used] = carry -019 -020 To be fixed for LTM 0.18 -021 */ -022 -023 /* shift left by a certain bit count */ -024 int -025 mp_mul_2d (mp_int * a, int b, mp_int * c) -026 \{ -027 mp_digit d; -028 int res; -029 -030 /* copy */ -031 if (a != c) \{ -032 if ((res = mp_copy (a, c)) != MP_OKAY) \{ -033 return res; -034 \} -035 \} -036 -037 if (c->alloc < (int)(c->used + b/DIGIT_BIT + 2)) \{ -038 if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 2)) != MP_OKAY) \{ -039 return res; -040 \} -041 \} -042 -043 /* shift by as many digits in the bit count */ -044 if (b >= (int)DIGIT_BIT) \{ -045 if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) \{ -046 return res; -047 \} -048 \} -049 c->used = c->alloc; -050 -051 /* shift any bit count < DIGIT_BIT */ -052 d = (mp_digit) (b % DIGIT_BIT); -053 if (d != 0) \{ -054 register mp_digit *tmpc, mask, r, rr; -055 register int x; -056 -057 /* bitmask for carries */ -058 mask = (((mp_digit)1) << d) - 1; -059 -060 /* alias */ -061 tmpc = c->dp; -062 -063 /* carry */ -064 r = 0; -065 for (x = 0; x < c->used; x++) \{ -066 /* get the higher bits of the current word */ -067 rr = (*tmpc >> (DIGIT_BIT - d)) & mask; -068 -069 /* shift the current word and OR in the carry */ -070 *tmpc = ((*tmpc << d) | r) & MP_MASK; -071 ++tmpc; -072 -073 /* set the carry to the carry bits of the current word */ -074 r = rr; -075 \} -076 \} -077 mp_clamp (c); -078 return MP_OKAY; -079 \} -\end{alltt} -\end{small} - -Notes to be revised when code is updated. -- Tom - -\subsection{Division by Power of Two} - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_div\_2d}. \\ -\textbf{Input}. One mp\_int $a$ and an integer $b$ \\ -\textbf{Output}. $c \leftarrow \lfloor a / 2^b \rfloor, d \leftarrow a \mbox{ (mod }2^b\mbox{)}$. \\ -\hline \\ -1. If $b \le 0$ then do \\ -\hspace{3mm}1.1 $c \leftarrow a$ (\textit{mp\_copy}) \\ -\hspace{3mm}1.2 $d \leftarrow 0$ (\textit{mp\_zero}) \\ -\hspace{3mm}1.3 Return(\textit{MP\_OKAY}). \\ -2. $c \leftarrow a$ \\ -3. $d \leftarrow a \mbox{ (mod }2^b\mbox{)}$ (\textit{mp\_mod\_2d}) \\ -4. If $b \ge lg(\beta)$ then do \\ -\hspace{3mm}4.1 $c \leftarrow \lfloor c/\beta^{\lfloor b/lg(\beta) \rfloor} \rfloor$ (\textit{mp\_rshd}). \\ -5. $k \leftarrow b \mbox{ (mod }lg(\beta)\mbox{)}$ \\ -6. If $k \ne 0$ then do \\ -\hspace{3mm}6.1 $mask \leftarrow 2^k$ \\ -\hspace{3mm}6.2 $r \leftarrow 0$ \\ -\hspace{3mm}6.3 for $n$ from $c.used - 1$ to $0$ do \\ -\hspace{6mm}6.3.1 $rr \leftarrow c_n \mbox{ (mod }mask\mbox{)}$ \\ -\hspace{6mm}6.3.2 $c_n \leftarrow (c_n >> k) + (r << (lg(\beta) - k))$ \\ -\hspace{6mm}6.3.3 $r \leftarrow rr$ \\ -7. Clamp excess digits of $c$. (\textit{mp\_clamp}) \\ -8. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_div\_2d} -\end{figure} - -\textbf{Algorithm mp\_div\_2d.} -This algorithm will divide an input $a$ by $2^b$ and produce the quotient and remainder. The algorithm is designed much like algorithm -mp\_mul\_2d by first using whole digit shifts then single precision shifts. This algorithm will also produce the remainder of the division -by using algorithm mp\_mod\_2d. - -\index{bn\_mp\_div\_2d.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_div\_2d.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* shift right by a certain bit count (store quotient in c, optional remaind - er in d) */ -018 int -019 mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) -020 \{ -021 mp_digit D, r, rr; -022 int x, res; -023 mp_int t; -024 -025 -026 /* if the shift count is <= 0 then we do no work */ -027 if (b <= 0) \{ -028 res = mp_copy (a, c); -029 if (d != NULL) \{ -030 mp_zero (d); -031 \} -032 return res; -033 \} -034 -035 if ((res = mp_init (&t)) != MP_OKAY) \{ -036 return res; -037 \} -038 -039 /* get the remainder */ -040 if (d != NULL) \{ -041 if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) \{ -042 mp_clear (&t); -043 return res; -044 \} -045 \} -046 -047 /* copy */ -048 if ((res = mp_copy (a, c)) != MP_OKAY) \{ -049 mp_clear (&t); -050 return res; -051 \} -052 -053 /* shift by as many digits in the bit count */ -054 if (b >= (int)DIGIT_BIT) \{ -055 mp_rshd (c, b / DIGIT_BIT); -056 \} -057 -058 /* shift any bit count < DIGIT_BIT */ -059 D = (mp_digit) (b % DIGIT_BIT); -060 if (D != 0) \{ -061 register mp_digit *tmpc, mask; -062 -063 /* mask */ -064 mask = (((mp_digit)1) << D) - 1; -065 -066 /* alias */ -067 tmpc = c->dp + (c->used - 1); -068 -069 /* carry */ -070 r = 0; -071 for (x = c->used - 1; x >= 0; x--) \{ -072 /* get the lower bits of this word in a temp */ -073 rr = *tmpc & mask; -074 -075 /* shift the current word and mix in the carry bits from the previous - word */ -076 *tmpc = (*tmpc >> D) | (r << (DIGIT_BIT - D)); -077 --tmpc; -078 -079 /* set the carry to the carry bits of the current word found above */ -080 r = rr; -081 \} -082 \} -083 mp_clamp (c); -084 if (d != NULL) \{ -085 mp_exch (&t, d); -086 \} -087 mp_clear (&t); -088 return MP_OKAY; -089 \} -\end{alltt} -\end{small} - -The implementation of algorithm mp\_div\_2d is slightly different than the algorithm specifies. The remainder $d$ may be optionally -ignored by passing \textbf{NULL} as the pointer to the mp\_int variable. The temporary mp\_int variable $t$ is used to hold the -result of the remainder operation until the end. This allows $d$ and $a$ to represent the same mp\_int without modifying $a$ before -the quotient is obtained. - -The remainder of the source code is essentially the same as the source code for mp\_mul\_2d. (-- Fix this paragraph up later, Tom). - -\subsection{Remainder of Division by Power of Two} - -The last algorithm in the series of polynomial basis power of two algorithms is calculating the remainder of division by $2^b$. This -algorithm benefits from the fact that in twos complement arithmetic $a \mbox{ (mod }2^b\mbox{)}$ is the same as $a$ AND $2^b - 1$. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_mod\_2d}. \\ -\textbf{Input}. One mp\_int $a$ and an integer $b$ \\ -\textbf{Output}. $c \leftarrow a \mbox{ (mod }2^b\mbox{)}$. \\ -\hline \\ -1. If $b \le 0$ then do \\ -\hspace{3mm}1.1 $c \leftarrow 0$ (\textit{mp\_zero}) \\ -\hspace{3mm}1.2 Return(\textit{MP\_OKAY}). \\ -2. If $b > a.used \cdot lg(\beta)$ then do \\ -\hspace{3mm}2.1 $c \leftarrow a$ (\textit{mp\_copy}) \\ -\hspace{3mm}2.2 Return the result of step 2.1. \\ -3. $c \leftarrow a$ \\ -4. If step 3 failed return(\textit{MP\_MEM}). \\ -5. for $n$ from $\lceil b / lg(\beta) \rceil$ to $c.used$ do \\ -\hspace{3mm}5.1 $c_n \leftarrow 0$ \\ -6. $k \leftarrow b \mbox{ (mod }lg(\beta)\mbox{)}$ \\ -7. $c_{\lfloor b / lg(\beta) \rfloor} \leftarrow c_{\lfloor b / lg(\beta) \rfloor} \mbox{ (mod }2^{k}\mbox{)}$. \\ -8. Clamp excess digits of $c$. (\textit{mp\_clamp}) \\ -9. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_mod\_2d} -\end{figure} - -\textbf{Algorithm mp\_mod\_2d.} -This algorithm will quickly calculate the value of $a \mbox{ (mod }2^b\mbox{)}$. First if $b$ is less than or equal to zero the -result is set to zero. If $b$ is greater than the number of bits in $a$ then it simply copies $a$ to $c$ and returns. Otherwise, $a$ -is copied to $b$, leading digits are removed and the remaining leading digit is trimed to the exact bit count. - -\index{bn\_mp\_mod\_2d.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_mod\_2d.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* calc a value mod 2\b */ -018 int -019 mp_mod_2d (mp_int * a, int b, mp_int * c) -020 \{ -021 int x, res; -022 -023 -024 /* if b is <= 0 then zero the int */ -025 if (b <= 0) \{ -026 mp_zero (c); -027 return MP_OKAY; -028 \} -029 -030 /* if the modulus is larger than the value than return */ -031 if (b > (int) (a->used * DIGIT_BIT)) \{ -032 res = mp_copy (a, c); -033 return res; -034 \} -035 -036 /* copy */ -037 if ((res = mp_copy (a, c)) != MP_OKAY) \{ -038 return res; -039 \} -040 -041 /* zero digits above the last digit of the modulus */ -042 for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x+ - +) \{ -043 c->dp[x] = 0; -044 \} -045 /* clear the digit that is not completely outside/inside the modulus */ -046 c->dp[b / DIGIT_BIT] &= -047 (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digi - t) 1)); -048 mp_clamp (c); -049 return MP_OKAY; -050 \} -\end{alltt} -\end{small} - --- Add comments later, Tom. - -\section*{Exercises} -\begin{tabular}{cl} -$\left [ 3 \right ] $ & Devise an algorithm that performs $a \cdot 2^b$ for generic values of $b$ \\ - & in $O(n)$ time. \\ - &\\ -$\left [ 3 \right ] $ & Devise an efficient algorithm to multiply by small low hamming \\ - & weight values such as $3$, $5$ and $9$. Extend it to handle all values \\ - & upto $64$ with a hamming weight less than three. \\ - &\\ -$\left [ 2 \right ] $ & Modify the preceding algorithm to handle values of the form \\ - & $2^k - 1$ as well. \\ - &\\ -$\left [ 3 \right ] $ & Using only algorithms mp\_mul\_2, mp\_div\_2 and mp\_add create an \\ - & algorithm to multiply two integers in roughly $O(2n^2)$ time for \\ - & any $n$-bit input. Note that the time of addition is ignored in the \\ - & calculation. \\ - & \\ -$\left [ 5 \right ] $ & Improve the previous algorithm to have a working time of at most \\ - & $O \left (2^{(k-1)}n + \left ({2n^2 \over k} \right ) \right )$ for an appropriate choice of $k$. Again ignore \\ - & the cost of addition. \\ - & \\ -$\left [ 2 \right ] $ & Devise a chart to find optimal values of $k$ for the previous problem \\ - & for $n = 64 \ldots 1024$ in steps of $64$. \\ - & \\ -$\left [ 2 \right ] $ & Using only algorithms mp\_abs and mp\_sub devise another method for \\ - & calculating the result of a signed comparison. \\ - & -\end{tabular} - -\chapter{Multiplication and Squaring} -\section{The Multipliers} -For most number theoretic problems including certain public key cryptographic algorithms, the ``multipliers'' form the most important subset of -algorithms of any multiple precision integer package. The set of multiplier algorithms include integer multiplication, squaring and modular reduction -where in each of the algorithms single precision multiplication is the dominant operation performed. This chapter will discuss integer multiplication -and squaring, leaving modular reductions for the subsequent chapter. - -The importance of the multiplier algorithms is for the most part driven by the fact that certain popular public key algorithms are based on modular -exponentiation, that is computing $d \equiv a^b \mbox{ (mod }c\mbox{)}$ for some arbitrary choice of $a$, $b$, $c$ and $d$. During a modular -exponentiation the majority\footnote{Roughly speaking a modular exponentiation will spend about 40\% of the time performing modular reductions, -35\% of the time performing squaring and 25\% of the time performing multiplications.} of the processor time is spent performing single precision -multiplications. - -For centuries general purpose multiplication has required a lengthly $O(n^2)$ process, whereby each digit of one multiplicand has to be multiplied -against every digit of the other multiplicand. Traditional long-hand multiplication is based on this process; while the techniques can differ the -overall algorithm used is essentially the same. Only ``recently'' have faster algorithms been studied. First Karatsuba multiplication was discovered in -1962. This algorithm can multiply two numbers with considerably fewer single precision multiplications when compared to the long-hand approach. -This technique led to the discovery of polynomial basis algorithms (\textit{good reference?}) and subquently Fourier Transform based solutions. - -\section{Multiplication} -\subsection{The Baseline Multiplication} -\index{baseline multiplication} -Computing the product of two integers in software can be achieved using a trivial adaptation of the standard $O(n^2)$ long-hand multiplication -algorithm that school children are taught. The algorithm is considered an $O(n^2)$ algoritn since for two $n$-digit inputs $n^2$ single precision -multiplications are required. More specifically for a $m$ and $n$ digit input $m \cdot n$ single precision multiplications are required. To -simplify most discussions, it will be assumed that the inputs have comparable number of digits. - -The ``baseline multiplication'' algorithm is designed to act as the ``catch-all'' algorithm, only to be used when the faster algorithms cannot be -used. This algorithm does not use any particularly interesting optimizations and should ideally be avoided if possible. One important -facet of this algorithm, is that it has been modified to only produce a certain amount of output digits as resolution. The importance of this -modification will become evident during the discussion of Barrett modular reduction. Recall that for a $n$ and $m$ digit input the product -will be at most $n + m$ digits. Therefore, this algorithm can be reduced to a full multiplier by having it produce $n + m$ digits of the product. - -Recall from sub-section 5.2.2 the definition of $\gamma$ as the number of bits in the type \textbf{mp\_digit}. We shall now extend the variable set to -include $\alpha$ which shall represent the number of bits in the type \textbf{mp\_word}. This implies that $2^{\alpha} > 2 \cdot \beta^2$. The -constant $\delta = 2^{\alpha - 2lg(\beta)}$ will represent the maximal weight of any column in a product (\textit{see sub-section 6.2.2 for more information}). - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{s\_mp\_mul\_digs}. \\ -\textbf{Input}. mp\_int $a$, mp\_int $b$ and an integer $digs$ \\ -\textbf{Output}. $c \leftarrow \vert a \vert \cdot \vert b \vert \mbox{ (mod }\beta^{digs}\mbox{)}$. \\ -\hline \\ -1. If min$(a.used, b.used) < \delta$ then do \\ -\hspace{3mm}1.1 Calculate $c = \vert a \vert \cdot \vert b \vert$ by the Comba method (\textit{see algorithm~\ref{fig:COMBAMULT}}). \\ -\hspace{3mm}1.2 Return the result of step 1.1 \\ -\\ -Allocate and initialize a temporary mp\_int. \\ -2. Init $t$ to be of size $digs$ \\ -3. If step 2 failed return(\textit{MP\_MEM}). \\ -4. $t.used \leftarrow digs$ \\ -\\ -Compute the product. \\ -5. for $ix$ from $0$ to $a.used - 1$ do \\ -\hspace{3mm}5.1 $u \leftarrow 0$ \\ -\hspace{3mm}5.2 $pb \leftarrow \mbox{min}(b.used, digs - ix)$ \\ -\hspace{3mm}5.3 If $pb < 1$ then goto step 6. \\ -\hspace{3mm}5.4 for $iy$ from $0$ to $pb - 1$ do \\ -\hspace{6mm}5.4.1 $\hat r \leftarrow t_{iy + ix} + a_{ix} \cdot b_{iy} + u$ \\ -\hspace{6mm}5.4.2 $t_{iy + ix} \leftarrow \hat r \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{6mm}5.4.3 $u \leftarrow \lfloor \hat r / \beta \rfloor$ \\ -\hspace{3mm}5.5 if $ix + pb < digs$ then do \\ -\hspace{6mm}5.5.1 $t_{ix + pb} \leftarrow u$ \\ -6. Clamp excess digits of $t$. \\ -7. Swap $c$ with $t$ \\ -8. Clear $t$ \\ -9. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm s\_mp\_mul\_digs} -\end{figure} - -\textbf{Algorithm s\_mp\_mul\_digs.} -This algorithm computes the unsigned product of two inputs $a$ and $b$, limited to an output precision of $digs$ digits. While it may seem -a bit awkward to modify the function from its simple $O(n^2)$ description, the usefulness of partial multipliers will arise in a subsequent -algorithm. The algorithm is loosely based on algorithm 14.12 from \cite[pp. 595]{HAC} and is similar to Algorithm M of Knuth \cite[pp. 268]{TAOCPV2}. -Algorithm s\_mp\_mul\_digs differs from these cited references since it can produce a variable output precision regardless of the precision of the -inputs. - -The first thing this algorithm checks for is whether a Comba multiplier can be used instead. If the minimum digit count of either -input is less than $\delta$, then the Comba method may be used instead. After the Comba method is ruled out, the baseline algorithm begins. A -temporary mp\_int variable $t$ is used to hold the intermediate result of the product. This allows the algorithm to be used to -compute products when either $a = c$ or $b = c$ without overwriting the inputs. - -All of step 5 is the infamous $O(n^2)$ multiplication loop slightly modified to only produce upto $digs$ digits of output. The $pb$ variable -is given the count of digits to read from $b$ inside the nested loop. If $pb \le 1$ then no more output digits can be produced and the algorithm -will exit the loop. The best way to think of the loops are as a series of $pb \times 1$ multiplications. That is, in each pass of the -innermost loop $a_{ix}$ is multiplied against $b$ and the result is added (\textit{with an appropriate shift}) to $t$. - -For example, consider multiplying $576$ by $241$. That is equivalent to computing $10^0(1)(576) + 10^1(4)(576) + 10^2(2)(576)$ which is best -visualized in the following table. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{|c|c|c|c|c|c|l|} -\hline && & 5 & 7 & 6 & \\ -\hline $\times$&& & 2 & 4 & 1 & \\ -\hline &&&&&&\\ - && & 5 & 7 & 6 & $10^0(1)(576)$ \\ - &2 & 3 & 6 & 1 & 6 & $10^1(4)(576) + 10^0(1)(576)$ \\ - 1 & 3 & 8 & 8 & 1 & 6 & $10^2(2)(576) + 10^1(4)(576) + 10^0(1)(576)$ \\ -\hline -\end{tabular} -\end{center} -\caption{Long-Hand Multiplication Diagram} -\end{figure} - -Each row of the product is added to the result after being shifted to the left (\textit{multiplied by a power of the radix}) by the appropriate -count. That is in pass $ix$ of the inner loop the product is added starting at the $ix$'th digit of the reult. - -Step 5.4.1 introduces the hat symbol (\textit{e.g. $\hat r$}) which represents a double precision variable. The multiplication on that step -is assumed to be a double wide output single precision multiplication. That is, two single precision variables are multiplied to produce a -double precision result. The step is somewhat optimized from a long-hand multiplication algorithm because the carry from the addition in step -5.4.1 is propagated through the nested loop. If the carry was not propagated immediately it would overflow the single precision digit -$t_{ix+iy}$ and the result would be lost. - -At step 5.5 the nested loop is finished and any carry that was left over should be forwarded. The carry does not have to be added to the $ix+pb$'th -digit since that digit is assumed to be zero at this point. However, if $ix + pb \ge digs$ the carry is not set as it would make the result -exceed the precision requested. - -\index{bn\_s\_mp\_mul\_digs.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_s\_mp\_mul\_digs.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* multiplies |a| * |b| and only computes upto digs digits of result -018 * HAC pp. 595, Algorithm 14.12 Modified so you can control how -019 * many digits of output are created. -020 */ -021 int -022 s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) -023 \{ -024 mp_int t; -025 int res, pa, pb, ix, iy; -026 mp_digit u; -027 mp_word r; -028 mp_digit tmpx, *tmpt, *tmpy; -029 -030 /* can we use the fast multiplier? */ -031 if (((digs) < MP_WARRAY) && -032 MIN (a->used, b->used) < -033 (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) \{ -034 return fast_s_mp_mul_digs (a, b, c, digs); -035 \} -036 -037 if ((res = mp_init_size (&t, digs)) != MP_OKAY) \{ -038 return res; -039 \} -040 t.used = digs; -041 -042 /* compute the digits of the product directly */ -043 pa = a->used; -044 for (ix = 0; ix < pa; ix++) \{ -045 /* set the carry to zero */ -046 u = 0; -047 -048 /* limit ourselves to making digs digits of output */ -049 pb = MIN (b->used, digs - ix); -050 -051 /* setup some aliases */ -052 /* copy of the digit from a used within the nested loop */ -053 tmpx = a->dp[ix]; -054 -055 /* an alias for the destination shifted ix places */ -056 tmpt = t.dp + ix; -057 -058 /* an alias for the digits of b */ -059 tmpy = b->dp; -060 -061 /* compute the columns of the output and propagate the carry */ -062 for (iy = 0; iy < pb; iy++) \{ -063 /* compute the column as a mp_word */ -064 r = ((mp_word) *tmpt) + -065 ((mp_word) tmpx) * ((mp_word) * tmpy++) + -066 ((mp_word) u); -067 -068 /* the new column is the lower part of the result */ -069 *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); -070 -071 /* get the carry word from the result */ -072 u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); -073 \} -074 /* set carry if it is placed below digs */ -075 if (ix + iy < digs) \{ -076 *tmpt = u; -077 \} -078 \} -079 -080 mp_clamp (&t); -081 mp_exch (&t, c); -082 -083 mp_clear (&t); -084 return MP_OKAY; -085 \} -\end{alltt} -\end{small} - -Lines 31 to 35 determine if the Comba method can be used first. The conditions for using the Comba routine are that min$(a.used, b.used) < \delta$ and -the number of digits of output is less than \textbf{MP\_WARRAY}. This new constant is used to control -the stack usage in the Comba routines. By default it is set to $\delta$ but can be reduced when memory is at a premium. - -Of particular importance is the calculation of the $ix+iy$'th column on lines 64, 65 and 66. Note how all of the -variables are cast to the type \textbf{mp\_word}, which is also the type of variable $\hat r$. That is to ensure that double precision operations -are used instead of single precision. The multiplication on line 65 makes use of a specific GCC optimizer behaviour. On the outset it looks like -the compiler will have to use a double precision multiplication to produce the result required. Such an operation would be horribly slow on most -processors and drag this to a crawl. However, GCC is smart enough to realize that double wide output single precision multipliers can be used. For -example, the instruction ``MUL'' on the x86 processor can multiply two 32-bit values and produce a 64-bit result. - -\subsection{Faster Multiplication by the ``Comba'' Method} - -One of the huge drawbacks of the ``baseline'' algorithms is that at the $O(n^2)$ level the carry must be computed and propagated upwards. This -makes the nested loop very sequential and hard to unroll and implement in parallel. The ``Comba'' \cite{COMBA} method is named after little known -(\textit{in cryptographic venues}) Paul G. Comba who described a method of implementing fast multipliers that do not require nested -carry fixup operations. As an interesting aside it seems that Paul Barrett describes a similar technique in -his 1986 paper \cite{BARRETT} written five years before. - -At the heart of the Comba technique is once again the long-hand algorithm. Except in this case a slight twist is placed on how -the columns of the result are produced. In the standard long-hand algorithm rows of products are produced then added together to form the -final result. In the baseline algorithm the columns are added together after each iteration to get the result instantaneously. - -In the Comba algorithm the columns of the result are produced entirely independently of each other. That is at the $O(n^2)$ level a -simple multiplication and addition step is performed. The carries of the columns are propagated after the nested loop to reduce the amount -of work requiored. Succintly the first step of the algorithm is to compute the product vector $\vec x$ as follows. - -\begin{equation} -\vec x_n = \sum_{i+j = n} a_ib_j, \forall n \in \lbrace 0, 1, 2, \ldots, i + j \rbrace -\end{equation} - -Where $\vec x_n$ is the $n'th$ column of the output vector. Consider the following example which computes the vector $\vec x$ for the multiplication -of $576$ and $241$. - -\newpage\begin{figure}[here] -\begin{small} -\begin{center} -\begin{tabular}{|c|c|c|c|c|c|} - \hline & & 5 & 7 & 6 & First Input\\ - \hline $\times$ & & 2 & 4 & 1 & Second Input\\ -\hline & & $1 \cdot 5 = 5$ & $1 \cdot 7 = 7$ & $1 \cdot 6 = 6$ & First pass \\ - & $4 \cdot 5 = 20$ & $4 \cdot 7+5=33$ & $4 \cdot 6+7=31$ & 6 & Second pass \\ - $2 \cdot 5 = 10$ & $2 \cdot 7 + 20 = 34$ & $2 \cdot 6+33=45$ & 31 & 6 & Third pass \\ -\hline 10 & 34 & 45 & 31 & 6 & Final Result \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Comba Multiplication Diagram} -\end{figure} - -At this point the vector $x = \left < 10, 34, 45, 31, 6 \right >$ is the result of the first step of the Comba multipler. -Now the columns must be fixed by propagating the carry upwards. The resultant vector will have one extra dimension over the input vector which is -congruent to adding a leading zero digit. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{Comba Fixup}. \\ -\textbf{Input}. Vector $\vec x$ of dimension $k$ \\ -\textbf{Output}. Vector $\vec x$ such that the carries have been propagated. \\ -\hline \\ -1. for $n$ from $0$ to $k - 1$ do \\ -\hspace{3mm}1.1 $\vec x_{n+1} \leftarrow \vec x_{n+1} + \lfloor \vec x_{n}/\beta \rfloor$ \\ -\hspace{3mm}1.2 $\vec x_{n} \leftarrow \vec x_{n} \mbox{ (mod }\beta\mbox{)}$ \\ -2. Return($\vec x$). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm Comba Fixup} -\end{figure} - -With that algorithm and $k = 5$ and $\beta = 10$ the following vector is produced $\vec x= \left < 1, 3, 8, 8, 1, 6 \right >$. In this case -$241 \cdot 576$ is in fact $138816$ and the procedure succeeded. If the algorithm is correct and as will be demonstrated shortly more -efficient than the baseline algorithm why not simply always use this algorithm? - -\subsubsection{Column Weight.} -At the nested $O(n^2)$ level the Comba method adds the product of two single precision variables to each column of the output -independently. A serious obstacle is if the carry is lost, due to lack of precision before the algorithm has a chance to fix -the carries. For example, in the multiplication of two three-digit numbers the third column of output will be the sum of -three single precision multiplications. If the precision of the accumulator for the output digits is less then $3 \cdot (\beta - 1)^2$ then -an overflow can occur and the carry information will be lost. For any $m$ and $n$ digit inputs the maximum weight of any column is -min$(m, n)$ which is fairly obvious. - -The maximum number of terms in any column of a product is known as the ``column weight'' and strictly governs when the algorithm can be used. Recall -from earlier that a double precision type has $\alpha$ bits of resolution and a single precision digit has $lg(\beta)$ bits of precision. Given these -two quantities we must not violate the following - -\begin{equation} -k \cdot \left (\beta - 1 \right )^2 < 2^{\alpha} -\end{equation} - -Which reduces to - -\begin{equation} -k \cdot \left ( \beta^2 - 2\beta + 1 \right ) < 2^{\alpha} -\end{equation} - -Let $\rho = lg(\beta)$ represent the number of bits in a single precision digit. By further re-arrangement of the equation the final solution is -found. - -\begin{equation} -k < {{2^{\alpha}} \over {\left (2^{2\rho} - 2^{\rho + 1} + 1 \right )}} -\end{equation} - -The defaults for LibTomMath are $\beta = 2^{28}$ and $\alpha = 2^{64}$ which means that $k$ is bounded by $k < 257$. In this configuration -the smaller input may not have more than $256$ digits if the Comba method is to be used. This is quite satisfactory for most applications since -$256$ digits would allow for numbers in the range of $0 \le x < 2^{7168}$ which, is much larger than most public key cryptographic algorithms require. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{fast\_s\_mp\_mul\_digs}. \\ -\textbf{Input}. mp\_int $a$, mp\_int $b$ and an integer $digs$ \\ -\textbf{Output}. $c \leftarrow \vert a \vert \cdot \vert b \vert \mbox{ (mod }\beta^{digs}\mbox{)}$. \\ -\hline \\ -Place an array of \textbf{MP\_WARRAY} double precision digits named $\hat W$ on the stack. \\ -1. If $c.alloc < digs$ then grow $c$ to $digs$ digits. (\textit{mp\_grow}) \\ -2. If step 1 failed return(\textit{MP\_MEM}).\\ -\\ -Zero the temporary array $\hat W$. \\ -3. for $n$ from $0$ to $digs - 1$ do \\ -\hspace{3mm}3.1 $\hat W_n \leftarrow 0$ \\ -\\ -Compute the columns. \\ -4. for $ix$ from $0$ to $a.used - 1$ do \\ -\hspace{3mm}4.1 $pb \leftarrow \mbox{min}(b.used, digs - ix)$ \\ -\hspace{3mm}4.2 If $pb < 1$ then goto step 5. \\ -\hspace{3mm}4.3 for $iy$ from $0$ to $pb - 1$ do \\ -\hspace{6mm}4.3.1 $\hat W_{ix+iy} \leftarrow \hat W_{ix+iy} + a_{ix}b_{iy}$ \\ -\\ -Propagate the carries upwards. \\ -5. $oldused \leftarrow c.used$ \\ -6. $c.used \leftarrow digs$ \\ -7. If $digs > 1$ then do \\ -\hspace{3mm}7.1. for $ix$ from $1$ to $digs - 1$ do \\ -\hspace{6mm}7.1.1 $\hat W_{ix} \leftarrow \hat W_{ix} + \lfloor \hat W_{ix-1} / \beta \rfloor$ \\ -\hspace{6mm}7.1.2 $c_{ix - 1} \leftarrow \hat W_{ix - 1} \mbox{ (mod }\beta\mbox{)}$ \\ -8. else do \\ -\hspace{3mm}8.1 $ix \leftarrow 0$ \\ -9. $c_{ix} \leftarrow \hat W_{ix} \mbox{ (mod }\beta\mbox{)}$ \\ -\\ -Zero excess digits. \\ -10. If $digs < oldused$ then do \\ -\hspace{3mm}10.1 for $n$ from $digs$ to $oldused - 1$ do \\ -\hspace{6mm}10.1.1 $c_n \leftarrow 0$ \\ -11. Clamp excessive digits of $c$. (\textit{mp\_clamp}) \\ -12. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm fast\_s\_mp\_mul\_digs} -\label{fig:COMBAMULT} -\end{figure} - -\textbf{Algorithm fast\_s\_mp\_mul\_digs.} -This algorithm performs the unsigned multiplication of $a$ and $b$ using the Comba method limited to $digs$ digits of precision. The algorithm -essentially peforms the same calculation as algorithm s\_mp\_mul\_digs, just much faster. - -The array $\hat W$ is meant to be on the stack when the algorithm is used. The size of the array does not change which is ideal. Note also that -unlike algorithm s\_mp\_mul\_digs no temporary mp\_int is required since the result is calculated directly in $\hat W$. - -The $O(n^2)$ loop on step four is where the Comba method's advantages begin to show through in comparison to the baseline algorithm. The lack of -a carry variable or propagation in this loop allows the loop to be performed with only single precision multiplication and additions. Now that each -iteration of the inner loop can be performed independent of the others the inner loop can be performed with a high level of parallelism. - -To measure the benefits of the Comba method over the baseline method consider the number of operations that are required. If the -cost in terms of time of a multiply and addition is $p$ and the cost of a carry propagation is $q$ then a baseline multiplication would require -$O \left ((p + q)n^2 \right )$ time to multiply two $n$-digit numbers. The Comba method requires only $O(pn^2 + qn)$ time, however in practice, -the speed increase is actually much more. With $O(n)$ space the algorithm can be reduced to $O(pn + qn)$ time by implementing the $n$ multiply -and addition operations in the nested loop in parallel. - -\index{bn\_fast\_s\_mp\_mul\_digs.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_fast\_s\_mp\_mul\_digs.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* Fast (comba) multiplier -018 * -019 * This is the fast column-array [comba] multiplier. It is -020 * designed to compute the columns of the product first -021 * then handle the carries afterwards. This has the effect -022 * of making the nested loops that compute the columns very -023 * simple and schedulable on super-scalar processors. -024 * -025 * This has been modified to produce a variable number of -026 * digits of output so if say only a half-product is required -027 * you don't have to compute the upper half (a feature -028 * required for fast Barrett reduction). -029 * -030 * Based on Algorithm 14.12 on pp.595 of HAC. -031 * -032 */ -033 int -034 fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) -035 \{ -036 int olduse, res, pa, ix; -037 mp_word W[MP_WARRAY]; -038 -039 /* grow the destination as required */ -040 if (c->alloc < digs) \{ -041 if ((res = mp_grow (c, digs)) != MP_OKAY) \{ -042 return res; -043 \} -044 \} -045 -046 /* clear temp buf (the columns) */ -047 memset (W, 0, sizeof (mp_word) * digs); -048 -049 /* calculate the columns */ -050 pa = a->used; -051 for (ix = 0; ix < pa; ix++) \{ -052 /* this multiplier has been modified to allow you to -053 * control how many digits of output are produced. -054 * So at most we want to make upto "digs" digits of output. -055 * -056 * this adds products to distinct columns (at ix+iy) of W -057 * note that each step through the loop is not dependent on -058 * the previous which means the compiler can easily unroll -059 * the loop without scheduling problems -060 */ -061 \{ -062 register mp_digit tmpx, *tmpy; -063 register mp_word *_W; -064 register int iy, pb; -065 -066 /* alias for the the word on the left e.g. A[ix] * A[iy] */ -067 tmpx = a->dp[ix]; -068 -069 /* alias for the right side */ -070 tmpy = b->dp; -071 -072 /* alias for the columns, each step through the loop adds a new -073 term to each column -074 */ -075 _W = W + ix; -076 -077 /* the number of digits is limited by their placement. E.g. -078 we avoid multiplying digits that will end up above the # of -079 digits of precision requested -080 */ -081 pb = MIN (b->used, digs - ix); -082 -083 for (iy = 0; iy < pb; iy++) \{ -084 *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); -085 \} -086 \} -087 -088 \} -089 -090 /* setup dest */ -091 olduse = c->used; -092 c->used = digs; -093 -094 \{ -095 register mp_digit *tmpc; -096 -097 /* At this point W[] contains the sums of each column. To get the -098 * correct result we must take the extra bits from each column and -099 * carry them down -100 * -101 * Note that while this adds extra code to the multiplier it -102 * saves time since the carry propagation is removed from the -103 * above nested loop.This has the effect of reducing the work -104 * from N*(N+N*c)==N**2 + c*N**2 to N**2 + N*c where c is the -105 * cost of the shifting. On very small numbers this is slower -106 * but on most cryptographic size numbers it is faster. -107 */ -108 tmpc = c->dp; -109 for (ix = 1; ix < digs; ix++) \{ -110 W[ix] += (W[ix - 1] >> ((mp_word) DIGIT_BIT)); -111 *tmpc++ = (mp_digit) (W[ix - 1] & ((mp_word) MP_MASK)); -112 \} -113 *tmpc++ = (mp_digit) (W[digs - 1] & ((mp_word) MP_MASK)); -114 -115 /* clear unused */ -116 for (; ix < olduse; ix++) \{ -117 *tmpc++ = 0; -118 \} -119 \} -120 -121 mp_clamp (c); -122 return MP_OKAY; -123 \} -\end{alltt} -\end{small} - -The memset on line 47 clears the initial $\hat W$ array to zero in a single step. Like the slower baseline multiplication -implementation a series of aliases (\textit{lines 67, 70 and 75}) are used to simplify the inner $O(n^2)$ loop. -In this case a new alias $\_\hat W$ has been added which refers to the double precision columns offset by $ix$ in each pass. - -The inner loop on lines 83, 84 and 85 is where the algorithm will spend the majority of the time, which is why it has been -stripped to the bones of any extra baggage\footnote{Hence the pointer aliases.}. On x86 processors the multiplication and additions amount to at the -very least five instructions (\textit{two loads, two additions, one multiply}) while on the ARMv4 processors they amount to only three -(\textit{one load, one store, one multiply-add}). For both of the x86 and ARMv4 processors the GCC compiler performs a good job at unrolling the loop -and scheduling the instructions so there are very few dependency stalls. - -In theory the difference between the baseline and comba algorithms is a mere $O(qn)$ time difference. However, in the $O(n^2)$ nested loop of the -baseline method there are dependency stalls as the algorithm must wait for the multiplier to finish before propagating the carry to the next -digit. As a result fewer of the often multiple execution units\footnote{The AMD Athlon has three execution units and the Intel P4 has four.} can -be simultaneously used. - -\subsection{Polynomial Basis Multiplication} -To break the $O(n^2)$ barrier in multiplication requires a completely different look at integer multiplication. In the following algorithms -the use of polynomial basis representation for two integers $a$ and $b$ as $f(x) = \sum_{i=0}^{n} a_i x^i$ and -$g(x) = \sum_{i=0}^{n} b_i x^i$ respectively, is required. In this system both $f(x)$ and $g(x)$ have $n + 1$ terms and are of the $n$'th degree. - -The product $a \cdot b \equiv f(x)g(x)$ is the polynomial $W(x) = \sum_{i=0}^{2n} w_i x^i$. The coefficients $w_i$ will -directly yield the desired product when $\beta$ is substituted for $x$. The direct solution to solve for the $2n + 1$ coefficients -requires $O(n^2)$ time and would in practice be slower than the Comba technique. - -However, numerical analysis theory indicates that only $2n + 1$ distinct points in $W(x)$ are required to determine the values of the $2n + 1$ unknown -coefficients. This means by finding $\zeta_y = W(y)$ for $2n + 1$ small values of $y$ the coefficients of $W(x)$ can be found with -Gaussian elimination. This technique is also occasionally refered to as the \textit{interpolation technique} (\textit{references please...}) since in -effect an interpolation based on $2n + 1$ points will yield a polynomial equivalent to $W(x)$. - -The coefficients of the polynomial $W(x)$ are unknown which makes finding $W(y)$ for any value of $y$ impossible. However, since -$W(x) = f(x)g(x)$ the equivalent $\zeta_y = f(y) g(y)$ can be used in its place. The benefit of this technique stems from the -fact that $f(y)$ and $g(y)$ are much smaller than either $a$ or $b$ respectively. As a result finding the $2n + 1$ relations required -by multiplying $f(y)g(y)$ involves multiplying integers that are much smaller than either of the inputs. - -When picking points to gather relations there are always three obvious points to choose, $y = 0, 1$ and $ \infty$. The $\zeta_0$ term -is simply the product $W(0) = w_0 = a_0 \cdot b_0$. The $\zeta_1$ term is the product -$W(1) = \left (\sum_{i = 0}^{n} a_i \right ) \left (\sum_{i = 0}^{n} b_i \right )$. The third point $\zeta_{\infty}$ is less obvious but rather -simple to explain. The $2n + 1$'th coefficient of $W(x)$ is numerically equivalent to the most significant column in an integer multiplication. -The point at $\infty$ is used symbolically to represent the most significant column, that is $W(\infty) = w_{2n} = a_nb_n$. Note that the -points at $y = 0$ and $\infty$ yield the coefficients $w_0$ and $w_{2n}$ directly. - -If more points are required they should be of small values and powers of two such as $2^q$ and the related \textit{mirror points} -$\left (2^q \right )^{2n} \cdot \zeta_{2^{-q}}$ for small values of $q$. The term ``mirror point'' stems from the fact that -$\left (2^q \right )^{2n} \cdot \zeta_{2^{-q}}$ can be calculated in the exact opposite fashion as $\zeta_{2^q}$. For -example, when $n = 2$ and $q = 1$ then following two equations are equivalent to the point $\zeta_{2}$ and its mirror. - -\begin{eqnarray} -\zeta_{2} = f(2)g(2) = (4a_2 + 2a_1 + a_0)(4b_2 + 2b_1 + b_0) \nonumber \\ -16 \cdot \zeta_{1 \over 2} = 4f({1\over 2}) \cdot 4g({1 \over 2}) = (a_2 + 2a_1 + 4a_0)(b_2 + 2b_1 + 4b_0) -\end{eqnarray} - -Using such points will allow the values of $f(y)$ and $g(y)$ to be independently calculated using only left shifts. For example, when $n = 2$ the -polynomial $f(2^q)$ is equal to $2^q((2^qa_2) + a_1) + a_0$. This technique of polynomial representation is known as Horner's method. - -As a general rule of the algorithm when the inputs are split into $n$ parts each there are $2n - 1$ multiplications. Each multiplication is of -multiplicands that have $n$ times fewer digits than the inputs. The asymptotic running time of this algorithm is -$O \left ( k^{lg_n(2n - 1)} \right )$ for $k$ digit inputs (\textit{assuming they have the same number of digits}). Figure~\ref{fig:exponent} -summarizes the exponents for various values of $n$. - -\begin{figure} -\begin{center} -\begin{tabular}{|c|c|c|} -\hline \textbf{Split into $n$ Parts} & \textbf{Exponent} & \textbf{Notes}\\ -\hline $2$ & $1.584962501$ & This is Karatsuba Multiplication. \\ -\hline $3$ & $1.464973520$ & This is Toom-Cook Multiplication. \\ -\hline $4$ & $1.403677461$ &\\ -\hline $5$ & $1.365212389$ &\\ -\hline $10$ & $1.278753601$ &\\ -\hline $100$ & $1.149426538$ &\\ -\hline $1000$ & $1.100270931$ &\\ -\hline $10000$ & $1.075252070$ &\\ -\hline -\end{tabular} -\end{center} -\caption{Asymptotic Running Time of Polynomial Basis Multiplication} -\label{fig:exponent} -\end{figure} - -At first it may seem like a good idea to choose $n = 1000$ since the exponent is approximately $1.1$. However, the overhead -of solving for the 2001 terms of $W(x)$ will certainly consume any savings the algorithm could offer for all but exceedingly large -numbers. - -\subsubsection{Cutoff Point} -The polynomial basis multiplication algorithms all require fewer single precision multiplications than a straight Comba approach. However, -the algorithms incur an overhead (\textit{at the $O(n)$ work level}) since they require a system of equations to be solved. This makes the -polynomial basis approach more costly to use with small inputs. - -Let $m$ represent the number of digits in the multiplicands (\textit{assume both multiplicands have the same number of digits}). There exists a -point $y$ such that when $m < y$ the polynomial basis algorithms are more costly than Comba, when $m = y$ they are roughly the same cost and -when $m > y$ the Comba methods are slower than the polynomial basis algorithms. - -The exact location of $y$ depends on several key architectural elements of the computer platform in question. - -\begin{enumerate} -\item The ratio of clock cycles for single precision multiplication versus other simpler operations such as addition, shifting, etc. For example -on the AMD Athlon the ratio is roughly $17 : 1$ while on the Intel P4 it is $29 : 1$. The higher the ratio in favour of multiplication the lower -the cutoff point $y$ will be. - -\item The complexity of the linear system of equations (\textit{for the coefficients of $W(x)$}) is. Generally speaking as the number of splits -grows the complexity grows substantially. Ideally solving the system will only involve addition, subtraction and shifting of integers. This -directly reflects on the ratio previous mentioned. - -\item To a lesser extent memory bandwidth and function call overheads. Provided the values are in the processor cache this is less of an -influence over the cutoff point. - -\end{enumerate} - -A clean cutoff point separation occurs when a point $y$ is found such that all of the cutoff point conditions are met. For example, if the point -is too low then there will be values of $m$ such that $m > y$ and the Comba method is still faster. Finding the cutoff points is fairly simple when -a high resolution timer is available. - -\subsection{Karatsuba Multiplication} -Karatsuba \cite{KARA} multiplication when originally proposed in 1962 was among the first set of algorithms to break the $O(n^2)$ barrier for -general purpose multiplication. Given two polynomial basis representations $f(x) = ax + b$ and $g(x) = cx + d$, Karatsuba proved with -light algebra \cite{KARAP} that the following polynomial is equivalent to multiplication of the two integers the polynomials represent. - -\begin{equation} -f(x) \cdot g(x) = acx^2 + ((a - b)(c - d) + ac + bd)x + bd -\end{equation} - -Using the observation that $ac$ and $bd$ could be re-used only three half sized multiplications would be required to produce the product. Applying -this algorithm recursively, the work factor becomes $O(n^{lg(3)})$ which is substantially better than the work factor $O(n^2)$ of the Comba technique. It turns -out what Karatsuba did not know or at least did not publish was that this is simply polynomial basis multiplication with the points -$\zeta_0$, $\zeta_{\infty}$ and $-\zeta_{-1}$. Consider the resultant system of equations. - -\begin{center} -\begin{tabular}{rcrcrcrc} -$\zeta_{0}$ & $=$ & & & & & $w_0$ \\ -$-\zeta_{-1}$ & $=$ & $-w_2$ & $+$ & $w_1$ & $-$ & $w_0$ \\ -$\zeta_{\infty}$ & $=$ & $w_2$ & & & & \\ -\end{tabular} -\end{center} - -By adding the first and last equation to the equation in the middle the term $w_1$ can be isolated and all three coefficients solved for. The simplicity -of this system of equations has made Karatsuba fairly popular. In fact the cutoff point is often fairly low\footnote{With LibTomMath 0.18 it is 70 and 109 digits for the Intel P4 and AMD Athlon respectively.} -making it an ideal algorithm to speed up certain public key cryptosystems such as RSA and Diffie-Hellman. It is worth noting that the point -$\zeta_1$ could be substituted for $-\zeta_{-1}$. In this case the first and third row are subtracted instead of added to the second row. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_karatsuba\_mul}. \\ -\textbf{Input}. mp\_int $a$ and mp\_int $b$ \\ -\textbf{Output}. $c \leftarrow \vert a \vert \cdot \vert b \vert$ \\ -\hline \\ -1. Init the following mp\_int variables: $x0$, $x1$, $y0$, $y1$, $t1$, $x0y0$, $x1y1$.\\ -2. If step 2 failed then return(\textit{MP\_MEM}). \\ -\\ -Split the input. e.g. $a = x1 \cdot \beta^B + x0$ \\ -3. $B \leftarrow \mbox{min}(a.used, b.used)/2$ \\ -4. $x0 \leftarrow a \mbox{ (mod }\beta^B\mbox{)}$ (\textit{mp\_mod\_2d}) \\ -5. $y0 \leftarrow b \mbox{ (mod }\beta^B\mbox{)}$ \\ -6. $x1 \leftarrow \lfloor a / \beta^B \rfloor$ (\textit{mp\_rshd}) \\ -7. $y1 \leftarrow \lfloor b / \beta^B \rfloor$ \\ -\\ -Calculate the three products. \\ -8. $x0y0 \leftarrow x0 \cdot y0$ (\textit{mp\_mul}) \\ -9. $x1y1 \leftarrow x1 \cdot y1$ \\ -10. $t1 \leftarrow x1 - x0$ (\textit{mp\_sub}) \\ -11. $x0 \leftarrow y1 - y0$ \\ -12. $t1 \leftarrow t1 \cdot x0$ \\ -\\ -Calculate the middle term. \\ -13. $x0 \leftarrow x0y0 + x1y1$ \\ -14. $t1 \leftarrow x0 - t1$ \\ -\\ -Calculate the final product. \\ -15. $t1 \leftarrow t1 \cdot \beta^B$ (\textit{mp\_lshd}) \\ -16. $x1y1 \leftarrow x1y1 \cdot \beta^{2B}$ \\ -17. $t1 \leftarrow x0y0 + t1$ \\ -18. $c \leftarrow t1 + x1y1$ \\ -19. Clear all of the temporary variables. \\ -20. Return(\textit{MP\_OKAY}).\\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_karatsuba\_mul} -\end{figure} - -\textbf{Algorithm mp\_karatsuba\_mul.} -This algorithm computes the unsigned product of two inputs using the Karatsuba multiplication algorithm. It is loosely based on the description -from Knuth \cite[pp. 294-295]{TAOCPV2}. - -\index{radix point} -In order to split the two inputs into their respective halves, a suitable \textit{radix point} must be chosen. The radix point chosen must -be used for both of the inputs meaning that it must be smaller than the smallest input. Step 3 chooses the radix point $B$ as half of the -smallest input \textbf{used} count. After the radix point is chosen the inputs are split into lower and upper halves. Step 4 and 5 -compute the lower halves. Step 6 and 7 computer the upper halves. - -After the halves have been computed the three intermediate half-size products must be computed. Step 8 and 9 compute the trivial products -$x0 \cdot y0$ and $x1 \cdot y1$. The mp\_int $x0$ is used as a temporary variable after $x1 - x0$ has been computed. By using $x0$ instead -of an additional temporary variable, the algorithm can avoid an addition memory allocation operation. - -The remaining steps 13 through 18 compute the Karatsuba polynomial through a variety of digit shifting and addition operations. - -\index{bn\_mp\_karatsuba\_mul.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_karatsuba\_mul.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* c = |a| * |b| using Karatsuba Multiplication using -018 * three half size multiplications -019 * -020 * Let B represent the radix [e.g. 2**DIGIT_BIT] and -021 * let n represent half of the number of digits in -022 * the min(a,b) -023 * -024 * a = a1 * B**n + a0 -025 * b = b1 * B**n + b0 -026 * -027 * Then, a * b => -028 a1b1 * B**2n + ((a1 - a0)(b1 - b0) + a0b0 + a1b1) * B + a0b0 -029 * -030 * Note that a1b1 and a0b0 are used twice and only need to be -031 * computed once. So in total three half size (half # of -032 * digit) multiplications are performed, a0b0, a1b1 and -033 * (a1-b1)(a0-b0) -034 * -035 * Note that a multiplication of half the digits requires -036 * 1/4th the number of single precision multiplications so in -037 * total after one call 25% of the single precision multiplications -038 * are saved. Note also that the call to mp_mul can end up back -039 * in this function if the a0, a1, b0, or b1 are above the threshold. -040 * This is known as divide-and-conquer and leads to the famous -041 * O(N**lg(3)) or O(N**1.584) work which is asymptopically lower than -042 * the standard O(N**2) that the baseline/comba methods use. -043 * Generally though the overhead of this method doesn't pay off -044 * until a certain size (N ~ 80) is reached. -045 */ -046 int -047 mp_karatsuba_mul (mp_int * a, mp_int * b, mp_int * c) -048 \{ -049 mp_int x0, x1, y0, y1, t1, x0y0, x1y1; -050 int B, err; -051 -052 /* default the return code to an error */ -053 err = MP_MEM; -054 -055 /* min # of digits */ -056 B = MIN (a->used, b->used); -057 -058 /* now divide in two */ -059 B = B / 2; -060 -061 /* init copy all the temps */ -062 if (mp_init_size (&x0, B) != MP_OKAY) -063 goto ERR; -064 if (mp_init_size (&x1, a->used - B) != MP_OKAY) -065 goto X0; -066 if (mp_init_size (&y0, B) != MP_OKAY) -067 goto X1; -068 if (mp_init_size (&y1, b->used - B) != MP_OKAY) -069 goto Y0; -070 -071 /* init temps */ -072 if (mp_init_size (&t1, B * 2) != MP_OKAY) -073 goto Y1; -074 if (mp_init_size (&x0y0, B * 2) != MP_OKAY) -075 goto T1; -076 if (mp_init_size (&x1y1, B * 2) != MP_OKAY) -077 goto X0Y0; -078 -079 /* now shift the digits */ -080 x0.sign = x1.sign = a->sign; -081 y0.sign = y1.sign = b->sign; -082 -083 x0.used = y0.used = B; -084 x1.used = a->used - B; -085 y1.used = b->used - B; -086 -087 \{ -088 register int x; -089 register mp_digit *tmpa, *tmpb, *tmpx, *tmpy; -090 -091 /* we copy the digits directly instead of using higher level functions -092 * since we also need to shift the digits -093 */ -094 tmpa = a->dp; -095 tmpb = b->dp; -096 -097 tmpx = x0.dp; -098 tmpy = y0.dp; -099 for (x = 0; x < B; x++) \{ -100 *tmpx++ = *tmpa++; -101 *tmpy++ = *tmpb++; -102 \} -103 -104 tmpx = x1.dp; -105 for (x = B; x < a->used; x++) \{ -106 *tmpx++ = *tmpa++; -107 \} -108 -109 tmpy = y1.dp; -110 for (x = B; x < b->used; x++) \{ -111 *tmpy++ = *tmpb++; -112 \} -113 \} -114 -115 /* only need to clamp the lower words since by definition the -116 * upper words x1/y1 must have a known number of digits -117 */ -118 mp_clamp (&x0); -119 mp_clamp (&y0); -120 -121 /* now calc the products x0y0 and x1y1 */ -122 /* after this x0 is no longer required, free temp [x0==t2]! */ -123 if (mp_mul (&x0, &y0, &x0y0) != MP_OKAY) -124 goto X1Y1; /* x0y0 = x0*y0 */ -125 if (mp_mul (&x1, &y1, &x1y1) != MP_OKAY) -126 goto X1Y1; /* x1y1 = x1*y1 */ -127 -128 /* now calc x1-x0 and y1-y0 */ -129 if (mp_sub (&x1, &x0, &t1) != MP_OKAY) -130 goto X1Y1; /* t1 = x1 - x0 */ -131 if (mp_sub (&y1, &y0, &x0) != MP_OKAY) -132 goto X1Y1; /* t2 = y1 - y0 */ -133 if (mp_mul (&t1, &x0, &t1) != MP_OKAY) -134 goto X1Y1; /* t1 = (x1 - x0) * (y1 - y0) */ -135 -136 /* add x0y0 */ -137 if (mp_add (&x0y0, &x1y1, &x0) != MP_OKAY) -138 goto X1Y1; /* t2 = x0y0 + x1y1 */ -139 if (mp_sub (&x0, &t1, &t1) != MP_OKAY) -140 goto X1Y1; /* t1 = x0y0 + x1y1 - (x1-x0)*(y1-y0) */ -141 -142 /* shift by B */ -143 if (mp_lshd (&t1, B) != MP_OKAY) -144 goto X1Y1; /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))<used, b->used) / 3; -033 -034 /* a = a2 * B**2 + a1 * B + a0 */ -035 if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) \{ -036 goto ERR; -037 \} -038 -039 if ((res = mp_copy(a, &a1)) != MP_OKAY) \{ -040 goto ERR; -041 \} -042 mp_rshd(&a1, B); -043 mp_mod_2d(&a1, DIGIT_BIT * B, &a1); -044 -045 if ((res = mp_copy(a, &a2)) != MP_OKAY) \{ -046 goto ERR; -047 \} -048 mp_rshd(&a2, B*2); -049 -050 /* b = b2 * B**2 + b1 * B + b0 */ -051 if ((res = mp_mod_2d(b, DIGIT_BIT * B, &b0)) != MP_OKAY) \{ -052 goto ERR; -053 \} -054 -055 if ((res = mp_copy(b, &b1)) != MP_OKAY) \{ -056 goto ERR; -057 \} -058 mp_rshd(&b1, B); -059 mp_mod_2d(&b1, DIGIT_BIT * B, &b1); -060 -061 if ((res = mp_copy(b, &b2)) != MP_OKAY) \{ -062 goto ERR; -063 \} -064 mp_rshd(&b2, B*2); -065 -066 /* w0 = a0*b0 */ -067 if ((res = mp_mul(&a0, &b0, &w0)) != MP_OKAY) \{ -068 goto ERR; -069 \} -070 -071 /* w4 = a2 * b2 */ -072 if ((res = mp_mul(&a2, &b2, &w4)) != MP_OKAY) \{ -073 goto ERR; -074 \} -075 -076 /* w1 = (a2 + 2(a1 + 2a0))(b2 + 2(b1 + 2b0)) */ -077 if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) \{ -078 goto ERR; -079 \} -080 if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) \{ -081 goto ERR; -082 \} -083 if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) \{ -084 goto ERR; -085 \} -086 if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) \{ -087 goto ERR; -088 \} -089 -090 if ((res = mp_mul_2(&b0, &tmp2)) != MP_OKAY) \{ -091 goto ERR; -092 \} -093 if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) \{ -094 goto ERR; -095 \} -096 if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) \{ -097 goto ERR; -098 \} -099 if ((res = mp_add(&tmp2, &b2, &tmp2)) != MP_OKAY) \{ -100 goto ERR; -101 \} -102 -103 if ((res = mp_mul(&tmp1, &tmp2, &w1)) != MP_OKAY) \{ -104 goto ERR; -105 \} -106 -107 /* w3 = (a0 + 2(a1 + 2a2))(b0 + 2(b1 + 2b2)) */ -108 if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) \{ -109 goto ERR; -110 \} -111 if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) \{ -112 goto ERR; -113 \} -114 if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) \{ -115 goto ERR; -116 \} -117 if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) \{ -118 goto ERR; -119 \} -120 -121 if ((res = mp_mul_2(&b2, &tmp2)) != MP_OKAY) \{ -122 goto ERR; -123 \} -124 if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) \{ -125 goto ERR; -126 \} -127 if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) \{ -128 goto ERR; -129 \} -130 if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) \{ -131 goto ERR; -132 \} -133 -134 if ((res = mp_mul(&tmp1, &tmp2, &w3)) != MP_OKAY) \{ -135 goto ERR; -136 \} -137 -138 -139 /* w2 = (a2 + a1 + a0)(b2 + b1 + b0) */ -140 if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) \{ -141 goto ERR; -142 \} -143 if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) \{ -144 goto ERR; -145 \} -146 if ((res = mp_add(&b2, &b1, &tmp2)) != MP_OKAY) \{ -147 goto ERR; -148 \} -149 if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) \{ -150 goto ERR; -151 \} -152 if ((res = mp_mul(&tmp1, &tmp2, &w2)) != MP_OKAY) \{ -153 goto ERR; -154 \} -155 -156 /* now solve the matrix -157 -158 0 0 0 0 1 -159 1 2 4 8 16 -160 1 1 1 1 1 -161 16 8 4 2 1 -162 1 0 0 0 0 -163 -164 using 12 subtractions, 4 shifts, -165 2 small divisions and 1 small multiplication -166 */ -167 -168 /* r1 - r4 */ -169 if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) \{ -170 goto ERR; -171 \} -172 /* r3 - r0 */ -173 if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) \{ -174 goto ERR; -175 \} -176 /* r1/2 */ -177 if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) \{ -178 goto ERR; -179 \} -180 /* r3/2 */ -181 if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) \{ -182 goto ERR; -183 \} -184 /* r2 - r0 - r4 */ -185 if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) \{ -186 goto ERR; -187 \} -188 if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) \{ -189 goto ERR; -190 \} -191 /* r1 - r2 */ -192 if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) \{ -193 goto ERR; -194 \} -195 /* r3 - r2 */ -196 if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) \{ -197 goto ERR; -198 \} -199 /* r1 - 8r0 */ -200 if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) \{ -201 goto ERR; -202 \} -203 if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) \{ -204 goto ERR; -205 \} -206 /* r3 - 8r4 */ -207 if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) \{ -208 goto ERR; -209 \} -210 if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) \{ -211 goto ERR; -212 \} -213 /* 3r2 - r1 - r3 */ -214 if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) \{ -215 goto ERR; -216 \} -217 if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) \{ -218 goto ERR; -219 \} -220 if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) \{ -221 goto ERR; -222 \} -223 /* r1 - r2 */ -224 if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) \{ -225 goto ERR; -226 \} -227 /* r3 - r2 */ -228 if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) \{ -229 goto ERR; -230 \} -231 /* r1/3 */ -232 if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) \{ -233 goto ERR; -234 \} -235 /* r3/3 */ -236 if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) \{ -237 goto ERR; -238 \} -239 -240 /* at this point shift W[n] by B*n */ -241 if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) \{ -242 goto ERR; -243 \} -244 if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) \{ -245 goto ERR; -246 \} -247 if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) \{ -248 goto ERR; -249 \} -250 if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) \{ -251 goto ERR; -252 \} -253 -254 if ((res = mp_add(&w0, &w1, c)) != MP_OKAY) \{ -255 goto ERR; -256 \} -257 if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) \{ -258 goto ERR; -259 \} -260 if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) \{ -261 goto ERR; -262 \} -263 if ((res = mp_add(&tmp1, c, c)) != MP_OKAY) \{ -264 goto ERR; -265 \} -266 -267 ERR: -268 mp_clear_multi(&w0, &w1, &w2, &w3, &w4, -269 &a0, &a1, &a2, &b0, &b1, -270 &b2, &tmp1, &tmp2, NULL); -271 return res; -272 \} -273 -\end{alltt} -\end{small} - --- Comments to be added during editing phase. - -\subsection{Signed Multiplication} -Now that algorithms to handle multiplications of every useful dimensions have been developed, a rather simple finishing touch is required. So far all -of the multiplication algorithms have been unsigned multiplications which leaves only a signed multiplication algorithm to be established. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_mul}. \\ -\textbf{Input}. mp\_int $a$ and mp\_int $b$ \\ -\textbf{Output}. $c \leftarrow a \cdot b$ \\ -\hline \\ -1. If $a.sign = b.sign$ then \\ -\hspace{3mm}1.1 $sign = MP\_ZPOS$ \\ -2. else \\ -\hspace{3mm}2.1 $sign = MP\_ZNEG$ \\ -3. If min$(a.used, b.used) \ge TOOM\_MUL\_CUTOFF$ then \\ -\hspace{3mm}3.1 $c \leftarrow a \cdot b$ using algorithm mp\_toom\_mul \\ -4. else if min$(a.used, b.used) \ge KARATSUBA\_MUL\_CUTOFF$ then \\ -\hspace{3mm}4.1 $c \leftarrow a \cdot b$ using algorithm mp\_karatsuba\_mul \\ -5. else \\ -\hspace{3mm}5.1 $digs \leftarrow a.used + b.used + 1$ \\ -\hspace{3mm}5.2 If $digs < MP\_ARRAY$ and min$(a.used, b.used) \le \delta$ then \\ -\hspace{6mm}5.2.1 $c \leftarrow a \cdot b \mbox{ (mod }\beta^{digs}\mbox{)}$ using algorithm fast\_s\_mp\_mul\_digs. \\ -\hspace{3mm}5.3 else \\ -\hspace{6mm}5.3.1 $c \leftarrow a \cdot b \mbox{ (mod }\beta^{digs}\mbox{)}$ using algorithm s\_mp\_mul\_digs. \\ -6. $c.sign \leftarrow sign$ \\ -7. Return the result of the unsigned multiplication performed. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_mul} -\end{figure} - -\textbf{Algorithm mp\_mul.} -This algorithm performs the signed multiplication of two inputs. It will make use of any of the three unsigned multiplication algorithms -available when the input is of appropriate size. The \textbf{sign} of the result is not set until the end of the algorithm since algorithm -s\_mp\_mul\_digs will clear it. - -\index{bn\_mp\_mul.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_mul.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* high level multiplication (handles sign) */ -018 int -019 mp_mul (mp_int * a, mp_int * b, mp_int * c) -020 \{ -021 int res, neg; -022 neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; -023 -024 if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) \{ -025 res = mp_toom_mul(a, b, c); -026 \} else if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) \{ -027 res = mp_karatsuba_mul (a, b, c); -028 \} else \{ -029 -030 /* can we use the fast multiplier? -031 * -032 * The fast multiplier can be used if the output will -033 * have less than MP_WARRAY digits and the number of -034 * digits won't affect carry propagation -035 */ -036 int digs = a->used + b->used + 1; -037 -038 if ((digs < MP_WARRAY) && -039 MIN(a->used, b->used) <= -040 (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) \{ -041 res = fast_s_mp_mul_digs (a, b, c, digs); -042 \} else \{ -043 res = s_mp_mul (a, b, c); -044 \} -045 -046 \} -047 c->sign = neg; -048 return res; -049 \} -\end{alltt} -\end{small} - -The implementation is rather simplistic and is not particularly noteworthy. Line 22 computes the sign of the result using the ``?'' -operator from the C programming language. Line 40 computes $\delta$ using the fact that $1 << k$ is equal to $2^k$. - -\section{Squaring} - -Squaring is a special case of multiplication where both multiplicands are equal. At first it may seem like there is no significant optimization -available but in fact there is. Consider the multiplication of $576$ against $241$. In total there will be nine single precision multiplications -performed which are $1\cdot 6$, $1 \cdot 7$, $1 \cdot 5$, $4 \cdot 6$, $4 \cdot 7$, $4 \cdot 5$, $2 \cdot 6$, $2 \cdot 7$ and $2 \cdot 5$. Now consider -the multiplication of $123$ against $123$. The nine products are $3 \cdot 3$, $3 \cdot 2$, $3 \cdot 1$, $2 \cdot 3$, $2 \cdot 2$, $2 \cdot 1$, -$1 \cdot 3$, $1 \cdot 2$ and $1 \cdot 1$. On closer inspection some of the products are equivalent. For example, $3 \cdot 2 = 2 \cdot 3$ -and $3 \cdot 1 = 1 \cdot 3$. - -For any $n$-digit input, there are ${{\left (n^2 + n \right)}\over 2}$ possible unique single precision multiplications required compared to the $n^2$ -required for multiplication. The following diagram gives an example of the operations required. - -\begin{figure}[here] -\begin{center} -\begin{tabular}{ccccc|c} -&&1&2&3&\\ -$\times$ &&1&2&3&\\ -\hline && $3 \cdot 1$ & $3 \cdot 2$ & $3 \cdot 3$ & Row 0\\ - & $2 \cdot 1$ & $2 \cdot 2$ & $2 \cdot 3$ && Row 1 \\ - $1 \cdot 1$ & $1 \cdot 2$ & $1 \cdot 3$ &&& Row 2 \\ -\end{tabular} -\end{center} -\caption{Squaring Optimization Diagram} -\end{figure} - -Starting from zero and numbering the columns from right to left a very simple pattern becomes obvious. For the purposes of this discussion let $x$ -represent the number being squared. The first observation is that in row $k$ the $2k$'th column of the product has a $\left (x_k \right)^2$ term in it. - -The second observation is that every column $j$ in row $k$ where $j \ne 2k$ is part of a double product. Every non-square term of a column will -appear twice hence the name ``double product''. Every odd column is made up entirely of double products. In fact every column is made up of double -products and at most one square (\textit{see the exercise section}). - -The third and final observation is that for row $k$ the first unique non-square term, that is, one that hasn't already appeared in an earlier row, -occurs at column $2k + 1$. For example, on row $1$ of the previous squaring, column one is part of the double product with column one from row zero. -Column two of row one is a square and column three is the first unique column. - -\subsection{The Baseline Squaring Algorithm} -The baseline squaring algorithm is meant to be a catch-all squaring algorithm. It will handle any of the input sizes that the faster routines -will not handle. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{s\_mp\_sqr}. \\ -\textbf{Input}. mp\_int $a$ \\ -\textbf{Output}. $b \leftarrow a^2$ \\ -\hline \\ -1. Init a temporary mp\_int of at least $2 \cdot a.used +1$ digits. (\textit{mp\_init\_size}) \\ -2. If step 1 failed return(\textit{MP\_MEM}) \\ -3. $t.used \leftarrow 2 \cdot a.used + 1$ \\ -4. For $ix$ from 0 to $a.used - 1$ do \\ -\hspace{3mm}Calculate the square. \\ -\hspace{3mm}4.1 $\hat r \leftarrow t_{2ix} + \left (a_{ix} \right )^2$ \\ -\hspace{3mm}4.2 $t_{2ix} \leftarrow \hat r \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{3mm}Calculate the double products after the square. \\ -\hspace{3mm}4.3 $u \leftarrow \lfloor \hat r / \beta \rfloor$ \\ -\hspace{3mm}4.4 For $iy$ from $ix + 1$ to $a.used - 1$ do \\ -\hspace{6mm}4.4.1 $\hat r \leftarrow 2 \cdot a_{ix}a_{iy} + t_{ix + iy} + u$ \\ -\hspace{6mm}4.4.2 $t_{ix + iy} \leftarrow \hat r \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{6mm}4.4.3 $u \leftarrow \lfloor \hat r / \beta \rfloor$ \\ -\hspace{3mm}Set the last carry. \\ -\hspace{3mm}4.5 While $u > 0$ do \\ -\hspace{6mm}4.5.1 $iy \leftarrow iy + 1$ \\ -\hspace{6mm}4.5.2 $\hat r \leftarrow t_{ix + iy} + u$ \\ -\hspace{6mm}4.5.3 $t_{ix + iy} \leftarrow \hat r \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{6mm}4.5.4 $u \leftarrow \lfloor \hat r / \beta \rfloor$ \\ -5. Clamp excess digits of $t$. (\textit{mp\_clamp}) \\ -6. Exchange $b$ and $t$. \\ -7. Clear $t$ (\textit{mp\_clear}) \\ -8. Return(\textit{MP\_OKAY}) \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm s\_mp\_sqr} -\end{figure} - -\textbf{Algorithm s\_mp\_sqr.} -This algorithm computes the square of an input using the three observations on squaring. It is based fairly faithfully on algorithm 14.16 of HAC -\cite[pp.596-597]{HAC}. Similar to algorithm s\_mp\_mul\_digs, a temporary mp\_int is allocated to hold the result of the squaring. This allows the -destination mp\_int to be the same as the source mp\_int. - -The outer loop of this algorithm begins on step 4. It is best to think of the outer loop as walking down the rows of the partial results, while -the inner loop computes the columns of the partial result. Step 4.1 and 4.2 compute the square term for each row, and step 4.3 and 4.4 propagate -the carry and compute the double products. - -The requirement that a mp\_word be able to represent the range $0 \le x < 2 \beta^2$ arises from this -very algorithm. The product $a_{ix}a_{iy}$ will lie in the range $0 \le x \le \beta^2 - 2\beta + 1$ which is obviously less than $\beta^2$ meaning that -when it is multiplied by two, it can be properly represented by a mp\_word. - -Similar to algorithm s\_mp\_mul\_digs, after every pass of the inner loop, the destination is correctly set to the sum of all of the partial -results calculated so far. This involves expensive carry propagation which will be eliminated in the next algorithm. - -\index{bn\_s\_mp\_sqr.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_s\_mp\_sqr.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ -018 int -019 s_mp_sqr (mp_int * a, mp_int * b) -020 \{ -021 mp_int t; -022 int res, ix, iy, pa; -023 mp_word r; -024 mp_digit u, tmpx, *tmpt; -025 -026 pa = a->used; -027 if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) \{ -028 return res; -029 \} -030 t.used = 2*pa + 1; -031 -032 for (ix = 0; ix < pa; ix++) \{ -033 /* first calculate the digit at 2*ix */ -034 /* calculate double precision result */ -035 r = ((mp_word) t.dp[2*ix]) + -036 ((mp_word) a->dp[ix]) * ((mp_word) a->dp[ix]); -037 -038 /* store lower part in result */ -039 t.dp[2*ix] = (mp_digit) (r & ((mp_word) MP_MASK)); -040 -041 /* get the carry */ -042 u = (r >> ((mp_word) DIGIT_BIT)); -043 -044 /* left hand side of A[ix] * A[iy] */ -045 tmpx = a->dp[ix]; -046 -047 /* alias for where to store the results */ -048 tmpt = t.dp + (2*ix + 1); -049 -050 for (iy = ix + 1; iy < pa; iy++) \{ -051 /* first calculate the product */ -052 r = ((mp_word) tmpx) * ((mp_word) a->dp[iy]); -053 -054 /* now calculate the double precision result, note we use -055 * addition instead of *2 since it's easier to optimize -056 */ -057 r = ((mp_word) * tmpt) + r + r + ((mp_word) u); -058 -059 /* store lower part */ -060 *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); -061 -062 /* get carry */ -063 u = (r >> ((mp_word) DIGIT_BIT)); -064 \} -065 /* propagate upwards */ -066 while (u != ((mp_digit) 0)) \{ -067 r = ((mp_word) * tmpt) + ((mp_word) u); -068 *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); -069 u = (r >> ((mp_word) DIGIT_BIT)); -070 \} -071 \} -072 -073 mp_clamp (&t); -074 mp_exch (&t, b); -075 mp_clear (&t); -076 return MP_OKAY; -077 \} -\end{alltt} -\end{small} - -Inside the outer loop (\textit{see line 32}) the square term is calculated on line 35. Line 42 extracts the carry from the square -term. Aliases for $a_{ix}$ and $t_{ix+iy}$ are initialized on lines 45 and 48 respectively. The doubling is performed using two -additions (\textit{see line 57}) since it is usually faster than shifting,if not at least as fast. - -\subsection{Faster Squaring by the ``Comba'' Method} -A major drawback to the baseline method is the requirement for single precision shifting inside the $O(n^2)$ nested loop. Squaring has an additional -drawback that it must double the product inside the inner loop as well. As for multiplication, the Comba technique can be used to eliminate these -performance hazards. - -The first obvious solution is to make an array of mp\_words which will hold all of the columns. This will indeed eliminate all of the carry -propagation operations from the inner loop. However, the inner product must still be doubled $O(n^2)$ times. The solution stems from the simple fact -that $2a + 2b + 2c = 2(a + b + c)$. That is the sum of all of the double products is equal to double the sum of all the products. For example, -$ab + ba + ac + ca = 2ab + 2ac = 2(ab + ac)$. - -However, we cannot simply double all of the columns, since the squares appear only once per row. The most practical solution is to have two mp\_word -arrays. One array will hold the squares and the other array will hold the double products. With both arrays the doubling and carry propagation can be -moved to a $O(n)$ work level outside the $O(n^2)$ level. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{fast\_s\_mp\_sqr}. \\ -\textbf{Input}. mp\_int $a$ \\ -\textbf{Output}. $b \leftarrow a^2$ \\ -\hline \\ -Place two arrays of \textbf{MP\_WARRAY} mp\_words named $\hat W$ and $\hat {X}$ on the stack. \\ -1. If $b.alloc < 2a.used + 1$ then grow $b$ to $2a.used + 1$ digits. (\textit{mp\_grow}). \\ -2. If step 1 failed return(\textit{MP\_MEM}). \\ -3. for $ix$ from $0$ to $2a.used + 1$ do \\ -\hspace{3mm}3.1 $\hat W_{ix} \leftarrow 0$ \\ -\hspace{3mm}3.2 $\hat {X}_{ix} \leftarrow 0$ \\ -4. for $ix$ from $0$ to $a.used - 1$ do \\ -\hspace{3mm}Compute the square.\\ -\hspace{3mm}4.1 $\hat {X}_{ix+ix} \leftarrow \left ( a_ix \right )^2$ \\ -\\ -\hspace{3mm}Compute the double products.\\ -\hspace{3mm}4.2 for $iy$ from $ix + 1$ to $a.used - 1$ do \\ -\hspace{6mm}4.2.1 $\hat W_{ix+iy} \leftarrow \hat W_{ix+iy} + a_{ix}a_{iy}$ \\ -5. $oldused \leftarrow b.used$ \\ -6. $b.used \leftarrow 2a.used + 1$ \\ -\\ -Double the products and propagate the carries simultaneously. \\ -7. $\hat W_0 \leftarrow 2 \hat W_0 + \hat {X}_0$ \\ -8. for $ix$ from $1$ to $2a.used$ do \\ -\hspace{3mm}8.1 $\hat W_{ix} \leftarrow 2 \hat W_{ix} + \hat {X}_{ix}$ \\ -\hspace{3mm}8.2 $\hat W_{ix} \leftarrow \hat W_{ix} + \lfloor \hat W_{ix - 1} / \beta \rfloor$ \\ -\hspace{3mm}8.3 $b_{ix-1} \leftarrow W_{ix-1} \mbox{ (mod }\beta\mbox{)}$ \\ -9. $b_{2a.used} \leftarrow \hat W_{2a.used} \mbox{ (mod }\beta\mbox{)}$ \\ -10. if $2a.used + 1 < oldused$ then do \\ -\hspace{3mm}10.1 for $ix$ from $2a.used + 1$ to $oldused$ do \\ -\hspace{6mm}10.1.1 $b_{ix} \leftarrow 0$ \\ -11. Clamp excess digits from $b$. (\textit{mp\_clamp}) \\ -12. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm fast\_s\_mp\_sqr} -\end{figure} - -\textbf{Algorithm fast\_s\_mp\_sqr.} -This algorithm computes the square of an input using the Comba technique. It is designed to be a replacement for algorithm s\_mp\_sqr when -the number of input digits is less than \textbf{MP\_WARRAY} and less than $\delta \over 2$. - -This routine requires two arrays of mp\_words to be placed on the stack. The first array $\hat W$ will hold the double products and the second -array $\hat X$ will hold the squares. Though only at most $MP\_WARRAY \over 2$ words of $\hat X$ are used, it has proven faster on most -processors to simply make it a full size array. - -The loop on step 3 will zero the two arrays to prepare them for the squaring step. Step 4.1 computes the squares of the product. Note how -it simply assigns the value into the $\hat X$ array. The nested loop on step 4.2 computes the doubles of the products. This loop -computes the sum of the products for each column. They are not doubled until later. - -After the squaring loop, the products stored in $\hat W$ musted be doubled and the carries propagated forwards. It makes sense to do both -operations at the same time. The expression $\hat W_{ix} \leftarrow 2 \hat W_{ix} + \hat {X}_{ix}$ computes the sum of the double product and the -squares in place. - -\index{bn\_fast\_s\_mp\_sqr.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_fast\_s\_mp\_sqr.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* fast squaring -018 * -019 * This is the comba method where the columns of the product -020 * are computed first then the carries are computed. This -021 * has the effect of making a very simple inner loop that -022 * is executed the most -023 * -024 * W2 represents the outer products and W the inner. -025 * -026 * A further optimizations is made because the inner -027 * products are of the form "A * B * 2". The *2 part does -028 * not need to be computed until the end which is good -029 * because 64-bit shifts are slow! -030 * -031 * Based on Algorithm 14.16 on pp.597 of HAC. -032 * -033 */ -034 int -035 fast_s_mp_sqr (mp_int * a, mp_int * b) -036 \{ -037 int olduse, newused, res, ix, pa; -038 mp_word W2[MP_WARRAY], W[MP_WARRAY]; -039 -040 /* calculate size of product and allocate as required */ -041 pa = a->used; -042 newused = pa + pa + 1; -043 if (b->alloc < newused) \{ -044 if ((res = mp_grow (b, newused)) != MP_OKAY) \{ -045 return res; -046 \} -047 \} -048 -049 /* zero temp buffer (columns) -050 * Note that there are two buffers. Since squaring requires -051 * a outter and inner product and the inner product requires -052 * computing a product and doubling it (a relatively expensive -053 * op to perform n**2 times if you don't have to) the inner and -054 * outer products are computed in different buffers. This way -055 * the inner product can be doubled using n doublings instead of -056 * n**2 -057 */ -058 memset (W, 0, newused * sizeof (mp_word)); -059 memset (W2, 0, newused * sizeof (mp_word)); -060 -061 /* This computes the inner product. To simplify the inner N**2 loop -062 * the multiplication by two is done afterwards in the N loop. -063 */ -064 for (ix = 0; ix < pa; ix++) \{ -065 /* compute the outer product -066 * -067 * Note that every outer product is computed -068 * for a particular column only once which means that -069 * there is no need todo a double precision addition -070 */ -071 W2[ix + ix] = ((mp_word) a->dp[ix]) * ((mp_word) a->dp[ix]); -072 -073 \{ -074 register mp_digit tmpx, *tmpy; -075 register mp_word *_W; -076 register int iy; -077 -078 /* copy of left side */ -079 tmpx = a->dp[ix]; -080 -081 /* alias for right side */ -082 tmpy = a->dp + (ix + 1); -083 -084 /* the column to store the result in */ -085 _W = W + (ix + ix + 1); -086 -087 /* inner products */ -088 for (iy = ix + 1; iy < pa; iy++) \{ -089 *_W++ += ((mp_word) tmpx) * ((mp_word) * tmpy++); -090 \} -091 \} -092 \} -093 -094 /* setup dest */ -095 olduse = b->used; -096 b->used = newused; -097 -098 /* now compute digits */ -099 \{ -100 register mp_digit *tmpb; -101 -102 /* double first value, since the inner products are -103 * half of what they should be -104 */ -105 W[0] += W[0] + W2[0]; -106 -107 tmpb = b->dp; -108 for (ix = 1; ix < newused; ix++) \{ -109 /* double/add next digit */ -110 W[ix] += W[ix] + W2[ix]; -111 -112 W[ix] = W[ix] + (W[ix - 1] >> ((mp_word) DIGIT_BIT)); -113 *tmpb++ = (mp_digit) (W[ix - 1] & ((mp_word) MP_MASK)); -114 \} -115 /* set the last value. Note even if the carry is zero -116 * this is required since the next step will not zero -117 * it if b originally had a value at b->dp[2*a.used] -118 */ -119 *tmpb++ = (mp_digit) (W[(newused) - 1] & ((mp_word) MP_MASK)); -120 -121 /* clear high digits */ -122 for (; ix < olduse; ix++) \{ -123 *tmpb++ = 0; -124 \} -125 \} -126 -127 mp_clamp (b); -128 return MP_OKAY; -129 \} -\end{alltt} -\end{small} - --- Write something deep and insightful later, Tom. - -\subsection{Polynomial Basis Squaring} -The same algorithm that performs optimal polynomial basis multiplication can be used to perform polynomial basis squaring. The minor exception -is that $\zeta_y = f(y)g(y)$ is actually equivalent to $\zeta_y = f(y)^2$ since $f(y) = g(y)$. Instead of performing $2n + 1$ -multiplications to find the $\zeta$ relations, squaring operations are performed instead. - -\subsection{Karatsuba Squaring} -Let $f(x) = ax + b$ represent the polynomial basis representation of a number to square. -Let $h(x) = \left ( f(x) \right )^2$ represent the square of the polynomial. The Karatsuba equation can be modified to square a -number with the following equation. - -\begin{equation} -h(x) = a^2x^2 + \left (a^2 + b^2 - (a - b)^2 \right )x + b^2 -\end{equation} - -Upon closer inspection this equation only requires the calculation of three half-sized squares: $a^2$, $b^2$ and $(a - b)^2$. As in -Karatsuba multiplication, this algorithm can be applied recursively on the input and will achieve an asymptotic running time of -$O \left ( n^{lg(3)} \right )$. - -You might ask yourself, if the asymptotic time of Karatsuba squaring and multiplication is the same, why not simply use the multiplication algorithm -instead? The answer to this arises from the cutoff point for squaring. As in multiplication there exists a cutoff point, at which the -time required for a Comba based squaring and a Karatsuba based squaring meet. Due to the overhead inherent in the Karatsuba method, the cutoff -point is fairly high. For example, on an AMD Athlon XP processor with $\beta = 2^{28}$, the cutoff point is around 127 digits. - -Consider squaring a 200 digit number with this technique. It will be split into two 100 digit halves which are subsequently squared. -The 100 digit halves will not be squared using Karatsuba, but instead using the faster Comba based squaring algorithm. If Karatsuba multiplication -were used instead, the 100 digit numbers would be squared with a slower Comba based multiplication. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_karatsuba\_sqr}. \\ -\textbf{Input}. mp\_int $a$ \\ -\textbf{Output}. $b \leftarrow a^2$ \\ -\hline \\ -1. Initialize the following temporary mp\_ints: $x0$, $x1$, $t1$, $t2$, $x0x0$ and $x1x1$. \\ -2. If any of the initializations on step 1 failed return(\textit{MP\_MEM}). \\ -\\ -Split the input. e.g. $a = x1\beta^B + x0$ \\ -3. $B \leftarrow \lfloor a.used / 2 \rfloor$ \\ -4. $x0 \leftarrow a \mbox{ (mod }\beta^B\mbox{)}$ (\textit{mp\_mod\_2d}) \\ -5. $x1 \leftarrow \lfloor a / \beta^B \rfloor$ (\textit{mp\_lshd}) \\ -\\ -Calculate the three squares. \\ -6. $x0x0 \leftarrow x0^2$ (\textit{mp\_sqr}) \\ -7. $x1x1 \leftarrow x1^2$ \\ -8. $t1 \leftarrow x1 - x0$ (\textit{mp\_sub}) \\ -9. $t1 \leftarrow t1^2$ \\ -\\ -Compute the middle term. \\ -10. $t2 \leftarrow x0x0 + x1x1$ (\textit{s\_mp\_add}) \\ -11. $t1 \leftarrow t2 - t1$ \\ -\\ -Compute final product. \\ -12. $t1 \leftarrow t1\beta^B$ (\textit{mp\_lshd}) \\ -13. $x1x1 \leftarrow x1x1\beta^{2B}$ \\ -14. $t1 \leftarrow t1 + x0x0$ \\ -15. $b \leftarrow t1 + x1x1$ \\ -16. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_karatsuba\_sqr} -\end{figure} - -\textbf{Algorithm mp\_karatsuba\_sqr.} -This algorithm computes the square of an input $a$ using the Karatsuba technique. This algorithm is very similar to the Karatsuba based -multiplication algorithm with the exception that the three half-size multiplications have been replaced with three half-size squarings. - -The radix point for squaring is simply placed exactly in the middle of the digits when the input has an odd number of digits, otherwise it is -placed just below the middle. Step 3, 4 and 5 compute the two halves required using $B$ -as the radix point. The first two squares in steps 6 and 7 are rather straightforward while the last square is of a more compact form. - -By expanding $\left (x1 - x0 \right )^2$, the $x1^2$ and $x0^2$ terms in the middle disappear, that is $x1^2 + x0^2 - (x1 - x0)^2 = 2 \cdot x0 \cdot x1$. -Now if $5n$ single precision additions and a squaring of $n$-digits is faster than multiplying two $n$-digit numbers and doubling then -this method is faster. Assuming no further recursions occur, the difference can be estimated with the following inequality. - -Let $p$ represent the cost of a single precision addition and $q$ the cost of a single precision multiplication both in terms of time\footnote{Or -machine clock cycles.}. - -\begin{equation} -5pn +{{q(n^2 + n)} \over 2} \le pn + qn^2 -\end{equation} - -For example, on an AMD Athlon XP processor $p = {1 \over 3}$ and $q = 6$. This implies that the following inequality should hold. -\begin{center} -\begin{tabular}{rcl} -${5n \over 3} + 3n^2 + 3n$ & $<$ & ${n \over 3} + 6n^2$ \\ -${5 \over 3} + 3n + 3$ & $<$ & ${1 \over 3} + 6n$ \\ -${13 \over 9}$ & $<$ & $n$ \\ -\end{tabular} -\end{center} - -This results in a cutoff point around $n = 2$. As a consequence it is actually faster to compute the middle term the ``long way'' on processors -where multiplication is substantially slower\footnote{On the Athlon there is a 1:17 ratio between clock cycles for addition and multiplication. On -the Intel P4 processor this ratio is 1:29 making this method even more beneficial. The only common exception is the ARMv4 processor which has a -ratio of 1:7. } than simpler operations such as addition. - -\index{bn\_mp\_karatsuba\_sqr.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_karatsuba\_sqr.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* Karatsuba squaring, computes b = a*a using three -018 * half size squarings -019 * -020 * See comments of mp_karatsuba_mul for details. It -021 * is essentially the same algorithm but merely -022 * tuned to perform recursive squarings. -023 */ -024 int -025 mp_karatsuba_sqr (mp_int * a, mp_int * b) -026 \{ -027 mp_int x0, x1, t1, t2, x0x0, x1x1; -028 int B, err; -029 -030 err = MP_MEM; -031 -032 /* min # of digits */ -033 B = a->used; -034 -035 /* now divide in two */ -036 B = B / 2; -037 -038 /* init copy all the temps */ -039 if (mp_init_size (&x0, B) != MP_OKAY) -040 goto ERR; -041 if (mp_init_size (&x1, a->used - B) != MP_OKAY) -042 goto X0; -043 -044 /* init temps */ -045 if (mp_init_size (&t1, a->used * 2) != MP_OKAY) -046 goto X1; -047 if (mp_init_size (&t2, a->used * 2) != MP_OKAY) -048 goto T1; -049 if (mp_init_size (&x0x0, B * 2) != MP_OKAY) -050 goto T2; -051 if (mp_init_size (&x1x1, (a->used - B) * 2) != MP_OKAY) -052 goto X0X0; -053 -054 \{ -055 register int x; -056 register mp_digit *dst, *src; -057 -058 src = a->dp; -059 -060 /* now shift the digits */ -061 dst = x0.dp; -062 for (x = 0; x < B; x++) \{ -063 *dst++ = *src++; -064 \} -065 -066 dst = x1.dp; -067 for (x = B; x < a->used; x++) \{ -068 *dst++ = *src++; -069 \} -070 \} -071 -072 x0.used = B; -073 x1.used = a->used - B; -074 -075 mp_clamp (&x0); -076 -077 /* now calc the products x0*x0 and x1*x1 */ -078 if (mp_sqr (&x0, &x0x0) != MP_OKAY) -079 goto X1X1; /* x0x0 = x0*x0 */ -080 if (mp_sqr (&x1, &x1x1) != MP_OKAY) -081 goto X1X1; /* x1x1 = x1*x1 */ -082 -083 /* now calc (x1-x0)**2 */ -084 if (mp_sub (&x1, &x0, &t1) != MP_OKAY) -085 goto X1X1; /* t1 = x1 - x0 */ -086 if (mp_sqr (&t1, &t1) != MP_OKAY) -087 goto X1X1; /* t1 = (x1 - x0) * (x1 - x0) */ -088 -089 /* add x0y0 */ -090 if (s_mp_add (&x0x0, &x1x1, &t2) != MP_OKAY) -091 goto X1X1; /* t2 = x0x0 + x1x1 */ -092 if (mp_sub (&t2, &t1, &t1) != MP_OKAY) -093 goto X1X1; /* t1 = x0x0 + x1x1 - (x1-x0)*(x1-x0) */ -094 -095 /* shift by B */ -096 if (mp_lshd (&t1, B) != MP_OKAY) -097 goto X1X1; /* t1 = (x0x0 + x1x1 - (x1-x0)*(x1-x0))<used >= TOOM_SQR_CUTOFF) \{ -023 res = mp_toom_sqr(a, b); -024 \} else if (a->used >= KARATSUBA_SQR_CUTOFF) \{ -025 res = mp_karatsuba_sqr (a, b); -026 \} else \{ -027 -028 /* can we use the fast multiplier? */ -029 if ((a->used * 2 + 1) < MP_WARRAY && -030 a->used < -031 (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) \{ -032 res = fast_s_mp_sqr (a, b); -033 \} else \{ -034 res = s_mp_sqr (a, b); -035 \} -036 \} -037 b->sign = MP_ZPOS; -038 return res; -039 \} -\end{alltt} -\end{small} - -\section*{Exercises} -\begin{tabular}{cl} -$\left [ 3 \right ] $ & Devise an efficient algorithm for selection of the radix point to handle inputs \\ - & that have different number of digits in Karatsuba multiplication. \\ - & \\ -$\left [ 3 \right ] $ & In section 6.3 the fact that every column of a squaring is made up \\ - & of double products and at most one square is stated. Prove this statement. \\ - & \\ -$\left [ 2 \right ] $ & In the Comba squaring algorithm half of the $\hat X$ variables are not used. \\ - & Revise algorithm fast\_s\_mp\_sqr to shrink the $\hat X$ array. \\ - & \\ -$\left [ 3 \right ] $ & Prove the equation for Karatsuba squaring. \\ - & \\ -$\left [ 1 \right ] $ & Prove that Karatsuba squaring requires $O \left (n^{lg(3)} \right )$ time. \\ - & \\ -$\left [ 2 \right ] $ & Determine the minimal ratio between addition and multiplication clock cycles \\ - & required for equation $6.7$ to be true. \\ - & \\ -\end{tabular} - -\chapter{Modular Reduction} -\section{Basics of Modular Reduction} -\index{modular residue} -Modular reduction is an operation that arises quite often within public key cryptography algorithms and various number theoretic algorithms, -such as factoring. Modular reduction algorithms are the third class of algorithms of the ``multipliers'' set. A number $a$ is said to be reduced -modulo another number $b$ by finding the remainder of the division $a/b$. - -Modular reduction is equivalent to solving for $r$ in the following equation. $a = bq + r$ where $q = \lfloor a/b \rfloor$. The result -$r$ is said to be ``congruent to $a$ modulo $b$'' which is also written as $r \equiv a \mbox{ (mod }b\mbox{)}$. In other vernacular $r$ is known as the -``modular residue'' which leads to ``quadratic residue''\footnote{That's fancy talk for $b \equiv a^2 \mbox{ (mod }p\mbox{)}$.} and -other forms of residues. - -\index{modulus} -Modular reductions are normally used to form finite groups such as fields and rings. For example, in the RSA public key algorithm \cite{RSAPAPER} -two private primes $p$ and $q$ are chosen which when multiplied $n = pq$ forms a composite modulus. When operations such as multiplication and -squaring are performed on units of the ring $\Z_n$ a finite multiplicative sub-group is formed. - -Modular reductions have a variety of other useful properties. For example, a number $x$ is a square if and only if it is a quadratic -residue modulo a prime. With a finite set of primes $B = \left < p_0, p_1, \ldots, p_n \right >$ a quick test for whether $x$ is square or not can -be performed\footnote{Provided none of the primes from $B$ divide $x$.}. Consider the figure~\ref{fig:QR} with the candiate $x = 955621$ a simple -set of modular reductions modulo $3, 5, \ldots, 11$ may detect whether $x$ is a square or not. In this case $955621 \equiv 7 \mbox{ (mod }11\mbox{)}$ -and since $7$ is not a quadratic residue modulo $11$ the number $955621$ is not a square. - -\begin{figure} -\begin{center} -\begin{tabular}{|c|l|} -\hline \textbf{Prime} & \textbf{Quadratic Residues} \\ -\hline $3$ & $1$ \\ -\hline $5$ & $1, 4$ \\ -\hline $7$ & $1, 2, 4$ \\ -\hline $11$ & $1, 3, 4, 5, 9$ \\ -\hline -\end{tabular} -\end{center} -\caption{Quadratic Residues for primes less than $13$} -\label{fig:QR} -\end{figure} - -The most common usage for performance driven modular reductions is in modular exponentiation algorithms. That is to compute -$d = a^b \mbox{ (mod }c\mbox{)}$ as fast as possible. As will be discussed in the subsequent chapter there exists fast algorithms for computing -modular exponentiations without having to perform (\textit{in this example}) $b - 1$ multiplications. These algorithms will produce partial -results in the range $0 \le x < c^2$ which can be taken advantage of to create several efficient algorithms. - -\section{The Barrett Reduction} -The Barrett reduction algorithm \cite{BARRETT} was inspired by fast division algorithms which multiply by the reciprocal to emulate -division. Barretts observation was that the residue $c$ of $a$ modulo $b$ is equal to - -\begin{equation} -c = a - b \cdot \lfloor a/b \rfloor -\end{equation} - -Since algorithms such as modular exponentiation would be using the same modulus extensively, typical DSP intuition would indicate the next step -would be to replace $a/b$ by a multiplication by the reciprocal. However, DSP intuition on its own will not work as these numbers are considerably -larger than the precision of common DSP floating point data types. It would take another common optimization to optimize the algorithm. - -\subsection{Fixed Point Arithmetic} -The trick used to optimize the above equation is based on a technique of emulating floating point data types with fixed precision integers. Fixed -point arithmetic would vastly popularlize the ``3d-shooter'' genre of games in the mid 1990s when floating point units were fairly slow. The idea behind -fixed point arithmetic is to take a normal $k$-bit integer data type and break it into $p$-bit integer and a $q$-bit fraction part -(\textit{where $p+q = k$}). - -In this system a $k$-bit integer $n$ would actually represent $n/2^q$. For example, with $q = 4$ the integer $n = 37$ would actually represent the -value $2.3125$. To multiply two fixed point numbers the integers are multiplied using traditional arithmetic and subsequently normalized. For example, -with $q = 4$ to multiply the integers $9$ and $5$ they must be converted to fixed point first by multiplying by $2^q$. Let $a = 9(2^q)$ -represent the fixed point representation of $9$ and $b = 5(2^q)$ represent the fixed point representation of $5$. The product $ab$ is equal to -$45(2^{2q})$ which when normalized produces $45(2^q)$. - -Using fixed point arithmetic division can be easily achieved by multiplying by the reciprocal. If $2^q$ is equivalent to one than $2^q/b$ is -equivalent to $1/b$ using real arithmetic. Using this fact dividing an integer $a$ by another integer $b$ can be achieved with the following -expression. - -\begin{equation} -\lfloor (a \cdot (\lfloor 2^q / b \rfloor))/2^q \rfloor -\end{equation} - -The precision of the division is proportional to the value of $q$. If the divisor $b$ is used frequently as is the case with -modular exponentiation pre-computing $2^q/b$ will allow a division to be performed with a multiplication and a right shift. Both operations -are considerably faster than division on most processors. - -Consider dividing $19$ by $5$. The correct result is $\lfloor 19/5 \rfloor = 3$. With $q = 3$ the reciprocal is $\lfloor 2^q/5 \rfloor = 1$ which -leads to a product of $19$ which when divided by $2^q$ produces $2$. However, with $q = 4$ the reciprocal is $\lfloor 2^q/5 \rfloor = 3$ and -the result of the emulated division is $\lfloor 3 \cdot 19 / 2^q \rfloor = 3$ which is correct. - -Plugging this form of divison into the original equation the following modular residue equation arises. - -\begin{equation} -c = a - b \cdot \lfloor (a \cdot (\lfloor 2^q / b \rfloor))/2^q \rfloor -\end{equation} - -Using the notation from \cite{BARRETT} the value of $\lfloor 2^q / b \rfloor$ will be represented by the $\mu$ symbol. Using the $\mu$ -variable also helps re-inforce the idea that it is meant to be computed once and re-used. - -\begin{equation} -c = a - b \cdot \lfloor (a \cdot \mu)/2^q \rfloor -\end{equation} - -Provided that $2^q > b^2$ this algorithm will produce a quotient that is either exactly correct or off by a value of one. Let $n$ represent -the number of digits in $b$. This algorithm requires approximately $2n^2$ single precision multiplications to produce the quotient and -another $n^2$ single precision multiplications to find the residue. In total $3n^2$ single precision multiplications are required to -reduce the number. - -For example, if $b = 1179677$ and $q = 41$ ($2^q > b^2$), then the reciprocal $\mu$ is equal to $\lfloor 2^q / b \rfloor = 1864089$. Consider reducing -$a = 180388626447$ modulo $b$ using the above reduction equation. The quotient using the new formula is $\lfloor (a \cdot \mu) / 2^q \rfloor = 152913$. -By subtracting $152913b$ from $a$ the correct residue $a \equiv 677346 \mbox{ (mod }b\mbox{)}$ is found. - -\subsection{Choosing a Radix Point} -Using the fixed point representation a modular reduction can be performed with $3n^2$ single precision multiplications. If that were the best -that could be achieved a full division might as well be used in its place. The key to optimizing the reduction is to reduce the precision of -the initial multiplication that finds the quotient. - -Let $a$ represent the number of which the residue is sought. Let $b$ represent the modulus used to find the residue. Let $m$ represent -the number of digits in $b$. For the purposes of this discussion we will assume that the number of digits in $a$ is $2m$. Dividing $a$ by -$b$ is the same as dividing a $2m$ digit integer by a $m$ digit integer. Digits below the $m - 1$'th digit of $a$ will contribute at most a value -of $1$ to the quotient because $\beta^k < b$ for any $0 \le k \le m - 1$. - -Since those digits do not contribute much to the quotient the observation is that they might as well be zero. However, if the digits -``might as well be zero'' they might as well not be there in the first place. Let $q_0 = \lfloor a/\beta^{m-1} \rfloor$ represent the input -with the zeroes trimmed. Now the modular reduction is trimmed to the almost equivalent equation - -\begin{equation} -c = a - b \cdot \lfloor (q_0 \cdot \mu) / \beta^{m+1} \rfloor -\end{equation} - -Note that the original divisor $2^q$ has been replaced with $\beta^{m+1}$. Also note that the exponent on the divisor when added to the amount $q_0$ -was shifted by equals $2m$. If the optimization had not been performed the divisor would have the exponent $2m$ so in the end the exponents -do ``add up''. Using the above equation the quotient $\lfloor (q_0 \cdot \mu) / \beta^{m+1} \rfloor$ can be off from the true quotient by at most -two implying that $0 \le a - b \cdot \lfloor (q_0 \cdot \mu) / \beta^{m+1} \rfloor < 3b$. By first subtracting $b$ times the quotient and then -conditionally subtracting $b$ once or twice the residue is found. - -The quotient is now found using $(m + 1)(m) = m^2 + m$ single precision multiplications and the residue with an additional $m^2$ single -precision multiplications. In total $2m^2 + m$ single precision multiplications are required which is considerably faster than the original -attempt. - -For example, let $\beta = 10$ represent the radix of the digits. Let $b = 9999$ represent the modulus which implies $m = 4$. Let $a = 99929878$ -represent the value of which the residue is desired. In this case $q = 8$ since $10^7 < 9999^2$ meaning that $\mu = \lfloor \beta^{q}/b \rfloor = 10001$. -With the new observation the multiplicand for the quotient is equal to $q_0 = \lfloor a / \beta^{m - 1} \rfloor = 99929$. The quotient is then -$\lfloor (q_0 \cdot \mu) / \beta^{m+1} \rfloor = 9993$. Subtracting $9993b$ from $a$ and the correct residue $a \equiv 9871 \mbox{ (mod }b\mbox{)}$ -is found. - -\subsection{Trimming the Quotient} -So far the reduction algorithm has been optimized from $3m^2$ single precision multiplications down to $2m^2 + m$ single precision multiplications. As -it stands now the algorithm is already fairly fast compared to a full integer division algorithm. However, there is still room for -optimization. - -After the first multiplication inside the quotient ($q_0 \cdot \mu$) the value is shifted right by $m + 1$ places effectively nullifying the lower -half of the product. It would be nice to be able to remove those digits from the product to effectively cut down the number of single precision -multiplications. If the number of digits in the modulus $m$ is far less than $\beta$ a full product is not required for the algorithm to work properly. -In fact the lower $m - 2$ digits will not affect the upper half of the product at all and do not need to be computed. - -The value of $\mu$ is a $m$-digit number and $q_0$ is a $m + 1$ digit number. Using a full multiplier $(m + 1)(m) = m^2 + m$ single precision -multiplications would be required. Using a multiplier that will only produce digits at and above the $m - 1$'th digit reduces the number -of single precision multiplications to ${m^2 + m} \over 2$ single precision multiplications. - -\subsection{Trimming the Residue} -After the quotient has been calculated it is used to reduce the input. As previously noted the algorithm is not exact and it can be off by a small -multiple of the modulus, that is $0 \le a - b \cdot \lfloor (q_0 \cdot \mu) / \beta^{m+1} \rfloor < 3b$. If $b$ is $m$ digits than the -result of reduction equation is a value of at most $m + 1$ digits (\textit{provided $3 < \beta$}) implying that the upper $m - 1$ digits are -implicitly zero. - -The next optimization arises from this very fact. Instead of computing $b \cdot \lfloor (q_0 \cdot \mu) / \beta^{m+1} \rfloor$ using a full -$O(m^2)$ multiplication algorithm only the lower $m+1$ digits of the product have to be computed. Similarly the value of $a$ can -be reduced modulo $\beta^{m+1}$ before the multiple of $b$ is subtracted which simplifes the subtraction as well. A multiplication that produces -only the lower $m+1$ digits requires ${m^2 + 3m - 2} \over 2$ single precision multiplications. - -With both optimizations in place the algorithm is the algorithm Barrett proposed. It requires $m^2 + 2m - 1$ single precision multiplications which -is considerably faster than the straightforward $3m^2$ method. - -\subsection{The Barrett Algorithm} -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_reduce}. \\ -\textbf{Input}. mp\_int $a$, mp\_int $b$ and $\mu = \lfloor \beta^{2m}/b \rfloor$ $(0 \le a < b^2, b > 1)$ \\ -\textbf{Output}. $c \leftarrow a \mbox{ (mod }b\mbox{)}$ \\ -\hline \\ -Let $m$ represent the number of digits in $b$. \\ -1. Make a copy of $a$ and store it in $q$. (\textit{mp\_init\_copy}) \\ -2. $q \leftarrow \lfloor q / \beta^{m - 1} \rfloor$ (\textit{mp\_rshd}) \\ -\\ -Produce the quotient. \\ -3. $q \leftarrow q \cdot \mu$ (\textit{note: only produce digits at or above $m-1$}) \\ -4. $q \leftarrow \lfloor q / \beta^{m + 1} \rfloor$ \\ -\\ -Subtract the multiple of modulus from the input. \\ -5. $c \leftarrow a \mbox{ (mod }\beta^{m+1}\mbox{)}$ (\textit{mp\_mod\_2d}) \\ -6. $q \leftarrow q \cdot b \mbox{ (mod }\beta^{m+1}\mbox{)}$ (\textit{s\_mp\_mul\_digs}) \\ -7. $c \leftarrow c - q$ (\textit{mp\_sub}) \\ -\\ -Add $\beta^{m+1}$ if a carry occured. \\ -8. If $c < 0$ then (\textit{mp\_cmp\_d}) \\ -\hspace{3mm}8.1 $q \leftarrow 1$ (\textit{mp\_set}) \\ -\hspace{3mm}8.2 $q \leftarrow q \cdot \beta^{m+1}$ (\textit{mp\_lshd}) \\ -\hspace{3mm}8.3 $c \leftarrow c + q$ \\ -\\ -Now subtract the modulus if the residue is too large (e.g. quotient too small). \\ -9. While $c \ge b$ do (\textit{mp\_cmp}) \\ -\hspace{3mm}9.1 $c \leftarrow c - b$ \\ -10. Clear $q$. \\ -11. Return(\textit{MP\_OKAY}) \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_reduce} -\end{figure} - -\textbf{Algorithm mp\_reduce.} -This algorithm will reduce the input $a$ modulo $b$ in place using the Barrett algorithm. It is loosely based on algorithm 14.42 of HAC -\cite[pp. 602]{HAC} which is based on the paper from Paul Barrett \cite{BARRETT}. The algorithm has several restrictions and assumptions which must be adhered to -for the algorithm to work. - -First the modulus $b$ is assumed to be positive and greater than one. If the modulus were less than or equal to one than subtracting -a multiple of it would either accomplish nothing or actually enlarge the input. The input $a$ must be in the range $0 \le a < b^2$ in order -for the quotient to have enough precision. Technically the algorithm will still work if $a \ge b^2$ but it will take much longer to finish. The -value of $\mu$ is passed as an argument to this algorithm and is assumed to be setup before the algorithm is used. - -Recall that the multiplication for the quotient on step 3 must only produce digits at or above the $m-1$'th position. An algorithm called -$s\_mp\_mul\_high\_digs$ which has not been presented is used to accomplish this task. This optimal algorithm can only be used if the number -of digits in $b$ is very much smaller than $\beta$. - -After the multiple of the modulus has been subtracted from $a$ the residue must be fixed up in case its negative. While it is known that -$a \ge b \cdot \lfloor (q_0 \cdot \mu) / \beta^{m+1} \rfloor$ only the lower $m+1$ digits are being used to compute the residue. In this case -the invariant $\beta^{m+1}$ must be added to the residue to make it positive again. - -The while loop at step 9 will subtract $b$ until the residue is less than $b$. If the algorithm is performed correctly this step is only -performed upto two times. However, if $a \ge b^2$ than it will iterate substantially more times than it should. - -\index{bn\_mp\_reduce.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_reduce.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* reduces x mod m, assumes 0 < x < m**2, mu is -018 * precomputed via mp_reduce_setup. -019 * From HAC pp.604 Algorithm 14.42 -020 */ -021 int -022 mp_reduce (mp_int * x, mp_int * m, mp_int * mu) -023 \{ -024 mp_int q; -025 int res, um = m->used; -026 -027 /* q = x */ -028 if ((res = mp_init_copy (&q, x)) != MP_OKAY) \{ -029 return res; -030 \} -031 -032 /* q1 = x / b**(k-1) */ -033 mp_rshd (&q, um - 1); -034 -035 /* according to HAC this is optimization is ok */ -036 if (((unsigned long) m->used) > (((mp_digit)1) << (DIGIT_BIT - 1))) \{ -037 if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) \{ -038 goto CLEANUP; -039 \} -040 \} else \{ -041 if ((res = s_mp_mul_high_digs (&q, mu, &q, um - 1)) != MP_OKAY) \{ -042 goto CLEANUP; -043 \} -044 \} -045 -046 /* q3 = q2 / b**(k+1) */ -047 mp_rshd (&q, um + 1); -048 -049 /* x = x mod b**(k+1), quick (no division) */ -050 if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) \{ -051 goto CLEANUP; -052 \} -053 -054 /* q = q * m mod b**(k+1), quick (no division) */ -055 if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) \{ -056 goto CLEANUP; -057 \} -058 -059 /* x = x - q */ -060 if ((res = mp_sub (x, &q, x)) != MP_OKAY) \{ -061 goto CLEANUP; -062 \} -063 -064 /* If x < 0, add b**(k+1) to it */ -065 if (mp_cmp_d (x, 0) == MP_LT) \{ -066 mp_set (&q, 1); -067 if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) -068 goto CLEANUP; -069 if ((res = mp_add (x, &q, x)) != MP_OKAY) -070 goto CLEANUP; -071 \} -072 -073 /* Back off if it's too big */ -074 while (mp_cmp (x, m) != MP_LT) \{ -075 if ((res = s_mp_sub (x, m, x)) != MP_OKAY) \{ -076 break; -077 \} -078 \} -079 -080 CLEANUP: -081 mp_clear (&q); -082 -083 return res; -084 \} -\end{alltt} -\end{small} - -The first multiplication that determines the quotient can be performed by only producing the digits from $m - 1$ and up. This essentially halves -the number of single precision multiplications required. However, the optimization is only safe if $\beta$ is much larger than the number of digits -in the modulus. In the source code this is evaluated on lines 36 to 44 where algorithm s\_mp\_mul\_high\_digs is used when it is -safe to do so. - -\subsection{The Barrett Setup Algorithm} -In order to use algorithm mp\_reduce the value of $\mu$ must be calculated in advance. Ideally this value should be computed once and stored for -future use so that the Barrett algorithm can be used without delay. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_reduce\_setup}. \\ -\textbf{Input}. mp\_int $a$ ($a > 1$) \\ -\textbf{Output}. $\mu \leftarrow \lfloor \beta^{2m}/a \rfloor$ \\ -\hline \\ -1. $\mu \leftarrow 2^{2 \cdot lg(\beta) \cdot m}$ (\textit{mp\_2expt}) \\ -2. $\mu \leftarrow \lfloor \mu / b \rfloor$ (\textit{mp\_div}) \\ -3. Return(\textit{MP\_OKAY}) \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_reduce\_setup} -\end{figure} - -\textbf{Algorithm mp\_reduce\_setup.} -This algorithm computes the reciprocal $\mu$ required for Barrett reduction. First $\beta^{2m}$ is calculated as $2^{2 \cdot lg(\beta) \cdot m}$ which -is equivalent and much faster. The final value is computed by taking the integer quotient of $\lfloor \mu / b \rfloor$. - -\index{bn\_mp\_reduce\_setup.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_reduce\_setup.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* pre-calculate the value required for Barrett reduction -018 * For a given modulus "b" it calulates the value required in "a" -019 */ -020 int -021 mp_reduce_setup (mp_int * a, mp_int * b) -022 \{ -023 int res; -024 -025 if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) \{ -026 return res; -027 \} -028 return mp_div (a, b, a, NULL); -029 \} -\end{alltt} -\end{small} - -This simple routine calculates the reciprocal $\mu$ required by Barrett reduction. Note the extended usage of algorithm mp\_div where the variable -which would received the remainder is passed as NULL. As will be discussed in section 9.1 the division routine allows both the quotient and the -remainder to be passed as NULL meaning to ignore the value. - -\section{The Montgomery Reduction} -Montgomery reduction\footnote{Thanks to Niels Ferguson for his insightful explanation of the algorithm.} \cite{MONT} is by far the most interesting -form of reduction in common use. It computes a modular residue which is not actually equal to the residue of the input yet instead equal to a -residue times a constant. However, as perplexing as this may sound the algorithm is relatively simple and very efficient. - -Throughout this entire section the variable $n$ will represent the modulus used to form the residue. As will be discussed shortly the value of -$n$ must be odd. The variable $x$ will represent the quantity of which the residue is sought. Similar to the Barrett algorithm the input -is restricted to $0 \le x < n^2$. To begin the description some simple number theory facts must be established. - -\textbf{Fact 1.} Adding $n$ to $x$ does not change the residue since in effect it adds one to the quotient $\lfloor x / n \rfloor$. Another way -to explain this is that $n$ (\textit{or multiples of $n$}) is congruent to zero modulo $n$. Adding zero will not change the value of the residue. - -\textbf{Fact 2.} If $x$ is even then performing a division by two in $\Z$ is congruent to $x \cdot 2^{-1} \mbox{ (mod }n\mbox{)}$. Actually -this is an application of the fact that if $x$ is evenly divisible by any $k \in \Z$ then division in $\Z$ will be congruent to -multiplication by $k^{-1}$ modulo $n$. - -From these two simple facts the following simple algorithm can be derived. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{Montgomery Reduction}. \\ -\textbf{Input}. Integer $x$, $n$ and $k$ \\ -\textbf{Output}. $2^{-k}x \mbox{ (mod }n\mbox{)}$ \\ -\hline \\ -1. for $t$ from $1$ to $k$ do \\ -\hspace{3mm}1.1 If $x$ is odd then \\ -\hspace{6mm}1.1.1 $x \leftarrow x + n$ \\ -\hspace{3mm}1.2 $x \leftarrow x/2$ \\ -2. Return $x$. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm Montgomery Reduction} -\end{figure} - -The algorithm reduces the input one bit at a time using the two congruencies stated previously. Inside the loop $n$, which is odd, is -added to $x$ if $x$ is odd. This forces $x$ to be even which allows the division by two in $\Z$ to be congruent to a modular division by two. Since -$x$ is assumed to be initially much larger than $n$ the addition of $n$ will contribute an insignificant magnitude to $x$. Let $r$ represent the -final result of the Montgomery algorithm. If $k > lg(n)$ and $0 \le x < n^2$ then the final result is limited to -$0 \le r < \lfloor x/2^k \rfloor + n$. As a result at most a single subtraction is required to get the residue desired. - -\begin{figure}[here] -\begin{small} -\begin{center} -\begin{tabular}{|c|l|} -\hline \textbf{Step number ($t$)} & \textbf{Result ($x$)} \\ -\hline $1$ & $x + n = 5812$, $x/2 = 2906$ \\ -\hline $2$ & $x/2 = 1453$ \\ -\hline $3$ & $x + n = 1710$, $x/2 = 855$ \\ -\hline $4$ & $x + n = 1112$, $x/2 = 556$ \\ -\hline $5$ & $x/2 = 278$ \\ -\hline $6$ & $x/2 = 139$ \\ -\hline $7$ & $x + n = 396$, $x/2 = 198$ \\ -\hline $8$ & $x/2 = 99$ \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Example of Montgomery Reduction (I)} -\label{fig:MONT1} -\end{figure} - -Consider the example in figure~\ref{fig:MONT1} which reduces $x = 5555$ modulo $n = 257$ when $k = 8$. The final result $r = 99$ which is actually -$2^{-8} \cdot 5555 \mbox{ (mod }257\mbox{)}$ can reveal the residue $x \equiv 158$ by multiplying by $2^8$ modulo $n$. - -Let $k = \lfloor lg(n) \rfloor + 1$ represent the number of bits in $n$. The current algorithm requires $2k^2$ single precision shifts -and $k^2$ single precision additions. At this rate the algorithm is most certainly slower than Barrett reduction and not terribly useful. -Fortunately there exists an alternative representation of the algorithm. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{Montgomery Reduction} (modified I). \\ -\textbf{Input}. Integer $x$, $n$ and $k$ \\ -\textbf{Output}. $2^{-k}x \mbox{ (mod }n\mbox{)}$ \\ -\hline \\ -1. for $t$ from $0$ to $k - 1$ do \\ -\hspace{3mm}1.1 If the $t$'th bit of $x$ is one then \\ -\hspace{6mm}1.1.1 $x \leftarrow x + 2^tn$ \\ -2. Return $x/2^k$. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm Montgomery Reduction (modified I)} -\end{figure} - -This algorithm is equivalent since $2^tn$ is a multiple of $n$ and the lower $k$ bits of $x$ are zero by step 2. The number of single -precision shifts has now been reduced from $2k^2$ to $k^2 + k$ which is only a small improvement. - -\begin{figure}[here] -\begin{small} -\begin{center} -\begin{tabular}{|c|l|} -\hline \textbf{Step number ($t$)} & \textbf{Result ($x$)} \\ -\hline $1$ & $x + 2^{0}n = 5812$ \\ -\hline $2$ & $5812$ \\ -\hline $3$ & $x + 2^{2}n = 6840$ \\ -\hline $4$ & $x + 2^{3}n = 8896$ \\ -\hline $5$ & $8896$ \\ -\hline $6$ & $8896$ \\ -\hline $7$ & $x + 2^{6}n = 25344$ \\ -\hline $8$ & $25344$ \\ -\hline -- & $x/2^k = 99$ \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Example of Montgomery Reduction (II)} -\label{fig:MONT2} -\end{figure} - -Figure~\ref{fig:MONT2} demonstrates the modified algorithm reducing $x = 4093$ modulo $n = 257$ with $k = 8$. -With this algorithm a single shift right at the end is the only right shift required to reduce the input instead of $k$ right shifts inside the -loop. Note that for the iterations $t = 2, 5, 6$ and $8$ where the result $x$ is not changed. In those iterations the $t$'th bit of $x$ is -zero and the appropriate multiple of $n$ does not need to be added to force the $t$'th bit of the result to zero. - -\subsection{Digit Based Montgomery Reduction} -Instead of computing the reduction on a bit-by-bit basis it is actually much faster to compute it on digit-by-digit basis. Consider the -previous algorithm re-written to compute the Montgomery reduction in this new fashion. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{Montgomery Reduction} (modified II). \\ -\textbf{Input}. Integer $x$, $n$ and $k$ \\ -\textbf{Output}. $\beta^{-k}x \mbox{ (mod }n\mbox{)}$ \\ -\hline \\ -1. for $t$ from $0$ to $k - 1$ do \\ -\hspace{3mm}1.1 $x \leftarrow x + \mu n \beta^t$ \\ -2. Return $x/\beta^k$. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm Montgomery Reduction (modified II)} -\end{figure} - -The value $\mu n \beta^t$ is a multiple of the modulus $n$ meaning that it will not change the residue. If the first digit of -the value $\mu n \beta^t$ equals the negative (modulo $\beta$) of the $t$'th digit of $x$ then the addition will result in a zero digit. This -problem breaks down to solving the following congruency. - -\begin{center} -\begin{tabular}{rcl} -$x_t + \mu n_0$ & $\equiv$ & $0 \mbox{ (mod }\beta\mbox{)}$ \\ -$\mu n_0$ & $\equiv$ & $-x_t \mbox{ (mod }\beta\mbox{)}$ \\ -$\mu$ & $\equiv$ & $-x_t/n_0 \mbox{ (mod }\beta\mbox{)}$ \\ -\end{tabular} -\end{center} - -In each iteration of the loop on step 1 a new value of $\mu$ must be calculated. The value of $-1/n_0 \mbox{ (mod }\beta\mbox{)}$ is used -extensively in this algorithm and should be precomputed. Let $\rho$ represent the negative of the modular inverse of $n_0$ modulo $\beta$. - -For example, let $\beta = 10$ represent the radix. Let $n = 17$ represent the modulus which implies $k = 2$ and $\rho \equiv 7$. Let $x = 33$ -represent the value to reduce. - -\newpage\begin{figure} -\begin{center} -\begin{tabular}{|c|c|c|} -\hline \textbf{Step ($t$)} & \textbf{Value of $x$} & \textbf{Value of $\mu$} \\ -\hline -- & $33$ & --\\ -\hline $0$ & $33 + \mu n = 50$ & $1$ \\ -\hline $1$ & $50 + \mu n \beta = 900$ & $5$ \\ -\hline -\end{tabular} -\end{center} -\caption{Example of Montgomery Reduction} -\end{figure} - -The final result $900$ is then divided by $\beta^k$ to produce the final result $9$. The first observation is that $9 \nequiv x \mbox{ (mod }n\mbox{)}$ -which implies the result is not the modular residue of $x$ modulo $n$. However, recall that the residue is actually multiplied by $\beta^{-k}$ in -the algorithm. To get the true residue the value must be multiplied by $\beta^k$. In this case $\beta^k \equiv 15 \mbox{ (mod }n\mbox{)}$ and -the correct residue is $9 \cdot 15 \equiv 16 \mbox{ (mod }n\mbox{)}$. - -\subsection{Baseline Montgomery Reduction} -The baseline Montgomery reduction algorithm will produce the residue for any size input. It is designed to be a catch-all algororithm for -Montgomery reductions. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_montgomery\_reduce}. \\ -\textbf{Input}. mp\_int $x$, mp\_int $n$ and a digit $\rho \equiv -1/n_0 \mbox{ (mod }n\mbox{)}$. \\ -\hspace{11.5mm}($0 \le x < n^2, n > 1, (n, \beta) = 1, \beta^k > n$) \\ -\textbf{Output}. $\beta^{-k}x \mbox{ (mod }n\mbox{)}$ \\ -\hline \\ -1. $digs \leftarrow 2n.used + 1$ \\ -2. If $digs < MP\_ARRAY$ and $m.used < \delta$ then \\ -\hspace{3mm}2.1 Use algorithm fast\_mp\_montgomery\_reduce instead. \\ -\\ -Setup $x$ for the reduction. \\ -3. If $x.alloc < digs$ then grow $x$ to $digs$ digits. \\ -4. $x.used \leftarrow digs$ \\ -\\ -Eliminate the lower $k$ digits. \\ -5. For $ix$ from $0$ to $k - 1$ do \\ -\hspace{3mm}5.1 $\mu \leftarrow x_{ix} \cdot \rho \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{3mm}5.2 $u \leftarrow 0$ \\ -\hspace{3mm}5.3 For $iy$ from $0$ to $k - 1$ do \\ -\hspace{6mm}5.3.1 $\hat r \leftarrow \mu n_{iy} + x_{ix + iy} + u$ \\ -\hspace{6mm}5.3.2 $x_{ix + iy} \leftarrow \hat r \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{6mm}5.3.3 $u \leftarrow \lfloor \hat r / \beta \rfloor$ \\ -\hspace{3mm}5.4 While $u > 0$ do \\ -\hspace{6mm}5.4.1 $iy \leftarrow iy + 1$ \\ -\hspace{6mm}5.4.2 $x_{ix + iy} \leftarrow x_{ix + iy} + u$ \\ -\hspace{6mm}5.4.3 $u \leftarrow \lfloor x_{ix+iy} / \beta \rfloor$ \\ -\hspace{6mm}5.4.4 $x_{ix + iy} \leftarrow x_{ix+iy} \mbox{ (mod }\beta\mbox{)}$ \\ -\\ -Divide by $\beta^k$ and fix up as required. \\ -6. $x \leftarrow \lfloor x / \beta^k \rfloor$ \\ -7. If $x \ge n$ then \\ -\hspace{3mm}7.1 $x \leftarrow x - n$ \\ -8. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_montgomery\_reduce} -\end{figure} - -\textbf{Algorithm mp\_montgomery\_reduce.} -This algorithm reduces the input $x$ modulo $n$ in place using the Montgomery reduction algorithm. The algorithm is loosely based -on algorithm 14.32 of \cite[pp.601]{HAC} except it merges the multiplication of $\mu n \beta^t$ with the addition in the inner loop. The -restrictions on this algorithm are fairly easy to adapt to. First $0 \le x < n^2$ bounds the input to numbers in the same range as -for the Barrett algorithm. Additionally $n > 1$ will ensure a modular inverse $\rho$ exists. $\rho$ must be calculated in -advance of this algorithm. Finally the variable $k$ is fixed and a pseudonym for $n.used$. - -Step 2 decides whether a faster Montgomery algorithm can be used. It is based on the Comba technique meaning that there are limits on -the size of the input. This algorithm is discussed in sub-section 7.3.3. - -Step 5 is the main reduction loop of the algorithm. The value of $\mu$ is calculated once per iteration in the outer loop. The inner loop -calculates $x + \mu n \beta^{ix}$ by multiplying $\mu n$ and adding the result to $x$ shifted by $ix$ digits. Both the addition and -multiplication are performed in the same loop to save time and memory. Step 5.4 will handle any additional carries that escape the inner loop. - -Using a quick inspection this algorithm requires $n$ single precision multiplications for the outer loop and $n^2$ single precision multiplications -in the inner loop. In total $n^2 + n$ single precision multiplications which compares favourably to Barrett at $n^2 + 2n - 1$ single precision -multiplications. - -\index{bn\_mp\_montgomery\_reduce.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_montgomery\_reduce.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* computes xR**-1 == x (mod N) via Montgomery Reduction */ -018 int -019 mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) -020 \{ -021 int ix, res, digs; -022 mp_digit mu; -023 -024 /* can the fast reduction [comba] method be used? -025 * -026 * Note that unlike in mp_mul you're safely allowed *less* -027 * than the available columns [255 per default] since carries -028 * are fixed up in the inner loop. -029 */ -030 digs = n->used * 2 + 1; -031 if ((digs < MP_WARRAY) && -032 n->used < -033 (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) \{ -034 return fast_mp_montgomery_reduce (x, n, rho); -035 \} -036 -037 /* grow the input as required */ -038 if (x->alloc < digs) \{ -039 if ((res = mp_grow (x, digs)) != MP_OKAY) \{ -040 return res; -041 \} -042 \} -043 x->used = digs; -044 -045 for (ix = 0; ix < n->used; ix++) \{ -046 /* mu = ai * m' mod b */ -047 mu = (x->dp[ix] * rho) & MP_MASK; -048 -049 /* a = a + mu * m * b**i */ -050 \{ -051 register int iy; -052 register mp_digit *tmpn, *tmpx, u; -053 register mp_word r; -054 -055 /* aliases */ -056 tmpn = n->dp; -057 tmpx = x->dp + ix; -058 -059 /* set the carry to zero */ -060 u = 0; -061 -062 /* Multiply and add in place */ -063 for (iy = 0; iy < n->used; iy++) \{ -064 r = ((mp_word) mu) * ((mp_word) * tmpn++) + -065 ((mp_word) u) + ((mp_word) * tmpx); -066 u = (r >> ((mp_word) DIGIT_BIT)); -067 *tmpx++ = (r & ((mp_word) MP_MASK)); -068 \} -069 /* propagate carries */ -070 while (u) \{ -071 *tmpx += u; -072 u = *tmpx >> DIGIT_BIT; -073 *tmpx++ &= MP_MASK; -074 \} -075 \} -076 \} -077 -078 /* x = x/b**n.used */ -079 mp_clamp(x); -080 mp_rshd (x, n->used); -081 -082 /* if A >= m then A = A - m */ -083 if (mp_cmp_mag (x, n) != MP_LT) \{ -084 return s_mp_sub (x, n, x); -085 \} -086 -087 return MP_OKAY; -088 \} -\end{alltt} -\end{small} - -This is the baseline implementation of the Montgomery reduction algorithm. Lines 30 to 35 determine if the Comba based -routine can be used instead. Line 47 computes the value of $\mu$ for that particular iteration of the outer loop. - -The multiplication $\mu n \beta^{ix}$ is performed in one step in the inner loop. The alias $tmpx$ refers to the $ix$'th digit of $x$ and -the alias $tmpn$ refers to the modulus $n$. - -\subsection{Faster ``Comba'' Montgomery Reduction} - -The Montgomery reduction requires fewer single precision multiplications than a Barrett reduction, however it is much slower due to the serial -nature of the inner loop. The Barrett reduction algorithm requires two slightly modified multipliers which can be implemented with the Comba -technique. The Montgomery reduction algorithm cannot directly use the Comba technique to any significant advantage since the inner loop calculates -a $k \times 1$ product $k$ times. - -The biggest obstacle is that at the $ix$'th iteration of the outer loop the value of $x_{ix}$ is required to calculate $\mu$. This means the -carries from $0$ to $ix - 1$ must have been propagated upwards to form a valid $ix$'th digit. The solution as it turns out is very simple. -Perform a Comba like multiplier and inside the outer loop just after the inner loop fix up the $ix + 1$'th digit by forwarding the carry. - -With this change in place the Montgomery reduction algorithm can be performed with a Comba style multiplication loop which substantially increases -the speed of the algorithm. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{fast\_mp\_montgomery\_reduce}. \\ -\textbf{Input}. mp\_int $x$, mp\_int $n$ and a digit $\rho \equiv -1/n_0 \mbox{ (mod }n\mbox{)}$. \\ -\hspace{11.5mm}($0 \le x < n^2, n > 1, (n, \beta) = 1, \beta^k > n$) \\ -\textbf{Output}. $\beta^{-k}x \mbox{ (mod }n\mbox{)}$ \\ -\hline \\ -Place an array of \textbf{MP\_WARRAY} mp\_word variables called $\hat W$ on the stack. \\ -1. if $x.alloc < n.used + 1$ then grow $x$ to $n.used + 1$ digits. \\ -Copy the digits of $x$ into the array $\hat W$ \\ -2. For $ix$ from $0$ to $x.used - 1$ do \\ -\hspace{3mm}2.1 $\hat W_{ix} \leftarrow x_{ix}$ \\ -3. For $ix$ from $x.used$ to $2n.used - 1$ do \\ -\hspace{3mm}3.1 $\hat W_{ix} \leftarrow 0$ \\ -Elimiate the lower $k$ digits. \\ -4. for $ix$ from $0$ to $n.used - 1$ do \\ -\hspace{3mm}4.1 $\mu \leftarrow \hat W_{ix} \cdot \rho \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{3mm}4.2 For $iy$ from $0$ to $n.used - 1$ do \\ -\hspace{6mm}4.2.1 $\hat W_{iy + ix} \leftarrow \hat W_{iy + ix} + \mu \cdot n_{iy}$ \\ -\hspace{3mm}4.3 $\hat W_{ix + 1} \leftarrow \hat W_{ix + 1} + \lfloor \hat W_{ix} / \beta \rfloor$ \\ -Propagate carries upwards. \\ -5. for $ix$ from $n.used$ to $2n.used + 1$ do \\ -\hspace{3mm}5.1 $\hat W_{ix + 1} \leftarrow \hat W_{ix + 1} + \lfloor \hat W_{ix} / \beta \rfloor$ \\ -Shift right and reduce modulo $\beta$ simultaneously. \\ -6. for $ix$ from $0$ to $n.used + 1$ do \\ -\hspace{3mm}6.1 $x_{ix} \leftarrow \hat W_{ix + n.used} \mbox{ (mod }\beta\mbox{)}$ \\ -Zero excess digits and fixup $x$. \\ -7. if $x.used > n.used + 1$ then do \\ -\hspace{3mm}7.1 for $ix$ from $n.used + 1$ to $x.used - 1$ do \\ -\hspace{6mm}7.1.1 $x_{ix} \leftarrow 0$ \\ -8. $x.used \leftarrow n.used + 1$ \\ -9. Clamp excessive digits of $x$. \\ -10. If $x \ge n$ then \\ -\hspace{3mm}10.1 $x \leftarrow x - n$ \\ -11. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm fast\_mp\_montgomery\_reduce} -\end{figure} - -\textbf{Algorithm fast\_mp\_montgomery\_reduce.} -This algorithm will compute the Montgomery reduction of $x$ modulo $n$ using the Comba technique. It is on most computer platforms significantly -faster than algorithm mp\_montgomery\_reduce and algorithm mp\_reduce (\textit{Barrett reduction}). The algorithm has the same restrictions -on the input as the baseline reduction algorithm. An additional two restrictions are imposed on this algorithm. The number of digits $k$ in the -the modulus $n$ must not violate $MP\_WARRAY > 2k +1$ and $n < \delta$. When $\beta = 2^{28}$ this algorithm can be used to reduce modulo -a modulus of at most $3,556$ bits in length. - -As in the other Comba reduction algorithms there is a $\hat W$ array which stores the columns of the product. It is initially filled with the -contents of $x$ with the excess digits zeroed. The reduction loop is very similar the to the baseline loop at heart. The multiplication on step -4.1 can be single precision only since $ab \mbox{ (mod }\beta\mbox{)} \equiv (a \mbox{ mod }\beta)(b \mbox{ mod }\beta)$. Some multipliers such -as those on the ARM processors take a variable length time to complete depending on the number of bytes of result it must produce. By performing -a single precision multiplication instead half the amount of time is spent. - -Also note that digit $\hat W_{ix}$ must have the carry from the $ix - 1$'th digit propagated upwards in order for this to work. That is what step -4.3 will do. In effect over the $n.used$ iterations of the outer loop the $n.used$'th lower columns all have the their carries propagated forwards. Note -how the upper bits of those same words are not reduced modulo $\beta$. This is because those values will be discarded shortly and there is no -point. - -Step 5 will propgate the remainder of the carries upwards. On step 6 the columns are reduced modulo $\beta$ and shifted simultaneously as they are -stored in the destination $x$. - -\index{bn\_fast\_mp\_montgomery\_reduce.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_fast\_mp\_montgomery\_reduce.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* computes xR**-1 == x (mod N) via Montgomery Reduction -018 * -019 * This is an optimized implementation of mp_montgomery_reduce -020 * which uses the comba method to quickly calculate the columns of the -021 * reduction. -022 * -023 * Based on Algorithm 14.32 on pp.601 of HAC. -024 */ -025 int -026 fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) -027 \{ -028 int ix, res, olduse; -029 mp_word W[MP_WARRAY]; -030 -031 /* get old used count */ -032 olduse = x->used; -033 -034 /* grow a as required */ -035 if (x->alloc < n->used + 1) \{ -036 if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) \{ -037 return res; -038 \} -039 \} -040 -041 \{ -042 register mp_word *_W; -043 register mp_digit *tmpx; -044 -045 _W = W; -046 tmpx = x->dp; -047 -048 /* copy the digits of a into W[0..a->used-1] */ -049 for (ix = 0; ix < x->used; ix++) \{ -050 *_W++ = *tmpx++; -051 \} -052 -053 /* zero the high words of W[a->used..m->used*2] */ -054 for (; ix < n->used * 2 + 1; ix++) \{ -055 *_W++ = 0; -056 \} -057 \} -058 -059 for (ix = 0; ix < n->used; ix++) \{ -060 /* mu = ai * m' mod b -061 * -062 * We avoid a double precision multiplication (which isn't required) -063 * by casting the value down to a mp_digit. Note this requires -064 * that W[ix-1] have the carry cleared (see after the inner loop) -065 */ -066 register mp_digit mu; -067 mu = (((mp_digit) (W[ix] & MP_MASK)) * rho) & MP_MASK; -068 -069 /* a = a + mu * m * b**i -070 * -071 * This is computed in place and on the fly. The multiplication -072 * by b**i is handled by offseting which columns the results -073 * are added to. -074 * -075 * Note the comba method normally doesn't handle carries in the -076 * inner loop In this case we fix the carry from the previous -077 * column since the Montgomery reduction requires digits of the -078 * result (so far) [see above] to work. This is -079 * handled by fixing up one carry after the inner loop. The -080 * carry fixups are done in order so after these loops the -081 * first m->used words of W[] have the carries fixed -082 */ -083 \{ -084 register int iy; -085 register mp_digit *tmpn; -086 register mp_word *_W; -087 -088 /* alias for the digits of the modulus */ -089 tmpn = n->dp; -090 -091 /* Alias for the columns set by an offset of ix */ -092 _W = W + ix; -093 -094 /* inner loop */ -095 for (iy = 0; iy < n->used; iy++) \{ -096 *_W++ += ((mp_word) mu) * ((mp_word) * tmpn++); -097 \} -098 \} -099 -100 /* now fix carry for next digit, W[ix+1] */ -101 W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT); -102 \} -103 -104 -105 \{ -106 register mp_digit *tmpx; -107 register mp_word *_W, *_W1; -108 -109 /* nox fix rest of carries */ -110 _W1 = W + ix; -111 _W = W + ++ix; -112 -113 for (; ix <= n->used * 2 + 1; ix++) \{ -114 *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT); -115 \} -116 -117 /* copy out, A = A/b**n -118 * -119 * The result is A/b**n but instead of converting from an -120 * array of mp_word to mp_digit than calling mp_rshd -121 * we just copy them in the right order -122 */ -123 tmpx = x->dp; -124 _W = W + n->used; -125 -126 for (ix = 0; ix < n->used + 1; ix++) \{ -127 *tmpx++ = *_W++ & ((mp_word) MP_MASK); -128 \} -129 -130 /* zero oldused digits, if the input a was larger than -131 * m->used+1 we'll have to clear the digits */ -132 for (; ix < olduse; ix++) \{ -133 *tmpx++ = 0; -134 \} -135 \} -136 -137 /* set the max used and clamp */ -138 x->used = n->used + 1; -139 mp_clamp (x); -140 -141 /* if A >= m then A = A - m */ -142 if (mp_cmp_mag (x, n) != MP_LT) \{ -143 return s_mp_sub (x, n, x); -144 \} -145 return MP_OKAY; -146 \} -\end{alltt} -\end{small} - -The $\hat W$ array is first filled with digits of $x$ on line 49 then the rest of the digits are zeroed on line 54. Both loops share -the same alias variables to make the code easier to read. - -The value of $\mu$ is calculated in an interesting fashion. First the value $\hat W_{ix}$ is reduced modulo $\beta$ and cast to a mp\_digit. This -forces the compiler to use a single precision multiplication and prevents any concerns about loss of precision. Line 101 fixes the carry -for the next iteration of the loop by propagating the carry from $\hat W_{ix}$ to $\hat W_{ix+1}$. - -The for loop on line 113 propagates the rest of the carries upwards through the columns. The for loop on line 126 reduces the columns -modulo $\beta$ and shifts them $k$ places at the same time. The alias $\_ \hat W$ actually refers to the array $\hat W$ starting at the $n.used$'th -digit, that is $\_ \hat W_{t} = \hat W_{n.used + t}$. - -\subsection{Montgomery Setup} -To calculate the variable $\rho$ a relatively simple algorithm will be required. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_montgomery\_setup}. \\ -\textbf{Input}. mp\_int $n$ ($n > 1$ and $(n, 2) = 1$) \\ -\textbf{Output}. $\rho \equiv -1/n_0 \mbox{ (mod }\beta\mbox{)}$ \\ -\hline \\ -1. $b \leftarrow n_0$ \\ -2. If $b$ is even return(\textit{MP\_VAL}) \\ -3. $x \leftarrow ((b + 2) \mbox{ AND } 4) << 1) + b$ \\ -4. for $k$ from 0 to $3$ do \\ -\hspace{3mm}4.1 $x \leftarrow x \cdot (2 - bx)$ \\ -5. $\rho \leftarrow \beta - x \mbox{ (mod }\beta\mbox{)}$ \\ -6. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_montgomery\_setup} -\end{figure} - -\textbf{Algorithm mp\_montgomery\_setup.} -This algorithm will calculate the value of $\rho$ required within the Montgomery reduction algorithms. It uses a very interesting trick -to calculate $1/n_0$ when $\beta$ is a power of two. - -\index{bn\_mp\_montgomery\_setup.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_montgomery\_setup.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* setups the montgomery reduction stuff */ -018 int -019 mp_montgomery_setup (mp_int * n, mp_digit * rho) -020 \{ -021 mp_digit x, b; -022 -023 /* fast inversion mod 2**k -024 * -025 * Based on the fact that -026 * -027 * XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n) -028 * => 2*X*A - X*X*A*A = 1 -029 * => 2*(1) - (1) = 1 -030 */ -031 b = n->dp[0]; -032 -033 if ((b & 1) == 0) \{ -034 return MP_VAL; -035 \} -036 -037 x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */ -038 x *= 2 - b * x; /* here x*a==1 mod 2**8 */ -039 #if !defined(MP_8BIT) -040 x *= 2 - b * x; /* here x*a==1 mod 2**16 */ -041 #endif -042 #if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT)) -043 x *= 2 - b * x; /* here x*a==1 mod 2**32 */ -044 #endif -045 #ifdef MP_64BIT -046 x *= 2 - b * x; /* here x*a==1 mod 2**64 */ -047 #endif -048 -049 /* rho = -1/m mod b */ -050 *rho = (((mp_digit) 1 << ((mp_digit) DIGIT_BIT)) - x) & MP_MASK; -051 -052 return MP_OKAY; -053 \} -\end{alltt} -\end{small} - -This source code computes the value of $\rho$ required to perform Montgomery reduction. It has been modified to avoid performing excess -multiplications when $\beta$ is not the default 28-bits. - -\section{The Diminished Radix Algorithm} -The Diminished Radix method of modular reduction \cite{DRMET} is a fairly clever technique which can be more efficient than either the Barrett -or Montgomery methods for certain forms of moduli. The technique is based on the following simple congruence. - -\begin{equation} -(x \mbox{ mod } n) + k \lfloor x / n \rfloor \equiv x \mbox{ (mod }(n - k)\mbox{)} -\end{equation} - -This observation was used in the MMB \cite{MMB} block cipher to create a diffusion primitive. It used the fact that if $n = 2^{31}$ and $k=1$ that -then a x86 multiplier could produce the 62-bit product and use the ``shrd'' instruction to perform a double-precision right shift. The proof -of the above equation is very simple. First write $x$ in the product form. - -\begin{equation} -x = qn + r -\end{equation} - -Now reduce both sides modulo $(n - k)$. - -\begin{equation} -x \equiv qk + r \mbox{ (mod }(n-k)\mbox{)} -\end{equation} - -The variable $n$ reduces modulo $n - k$ to $k$. By putting $q = \lfloor x/n \rfloor$ and $r = x \mbox{ mod } n$ -into the equation the original congruence is reproduced, thus concluding the proof. The following algorithm is based on this observation. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{Diminished Radix Reduction}. \\ -\textbf{Input}. Integer $x$, $n$, $k$ \\ -\textbf{Output}. $x \mbox{ mod } (n - k)$ \\ -\hline \\ -1. $q \leftarrow \lfloor x / n \rfloor$ \\ -2. $q \leftarrow k \cdot q$ \\ -3. $x \leftarrow x \mbox{ (mod }n\mbox{)}$ \\ -4. $x \leftarrow x + q$ \\ -5. If $x \ge (n - k)$ then \\ -\hspace{3mm}5.1 $x \leftarrow x - (n - k)$ \\ -\hspace{3mm}5.2 Goto step 1. \\ -6. Return $x$ \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm Diminished Radix Reduction} -\label{fig:DR} -\end{figure} - -This algorithm will reduce $x$ modulo $n - k$ and return the residue. If $0 \le x < (n - k)^2$ then the algorithm will loop almost always -once or twice and occasionally three times. For simplicity sake the value of $x$ is bounded by the following simple polynomial. - -\begin{equation} -0 \le x < n^2 + k^2 - 2nk -\end{equation} - -The true bound is $0 \le x < (n - k - 1)^2$ but this has quite a few more terms. The value of $q$ after step 1 is bounded by the following. - -\begin{equation} -q < n - 2k - k^2/n -\end{equation} - -Since $k^2$ is going to be considerably smaller than $n$ that term will always be zero. The value of $x$ after step 3 is bounded trivially as -$0 \le x < n$. By step four the sum $x + q$ is bounded by - -\begin{equation} -0 \le q + x < (k + 1)n - 2k^2 - 1 -\end{equation} - -With a second pass $q$ will be loosely bounded by $0 \le q < k^2$ after step 2 while $x$ will still be loosely bounded by $0 \le x < n$ after step 3. After the second pass it is highly unlike that the -sum in step 4 will exceed $n - k$. In practice fewer than three passes of the algorithm are required to reduce virtually every input in the -range $0 \le x < (n - k - 1)^2$. - -\begin{figure} -\begin{small} -\begin{center} -\begin{tabular}{|l|} -\hline -$x = 123456789, n = 256, k = 3$ \\ -\hline $q \leftarrow \lfloor x/n \rfloor = 482253$ \\ -$q \leftarrow q*k = 1446759$ \\ -$x \leftarrow x \mbox{ mod } n = 21$ \\ -$x \leftarrow x + q = 1446780$ \\ -$x \leftarrow x - (n - k) = 1446527$ \\ -\hline -$q \leftarrow \lfloor x/n \rfloor = 5650$ \\ -$q \leftarrow q*k = 16950$ \\ -$x \leftarrow x \mbox{ mod } n = 127$ \\ -$x \leftarrow x + q = 17077$ \\ -$x \leftarrow x - (n - k) = 16824$ \\ -\hline -$q \leftarrow \lfloor x/n \rfloor = 65$ \\ -$q \leftarrow q*k = 195$ \\ -$x \leftarrow x \mbox{ mod } n = 184$ \\ -$x \leftarrow x + q = 379$ \\ -$x \leftarrow x - (n - k) = 126$ \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Example Diminished Radix Reduction} -\label{fig:EXDR} -\end{figure} - -Figure~\ref{fig:EXDR} demonstrates the reduction of $x = 123456789$ modulo $n - k = 253$ when $n = 256$ and $k = 3$. Note that even while $x$ -is considerably larger than $(n - k - 1)^2 = 63504$ the algorithm still converges on the modular residue exceedingly fast. In this case only -three passes were required to find the residue $x \equiv 126$. - - -\subsection{Choice of Moduli} -On the surface this algorithm looks like a very expensive algorithm. It requires a couple of subtractions followed by multiplication and other -modular reductions. The usefulness of this algorithm becomes exceedingly clear when an appropriate moduli is chosen. - -Division in general is a very expensive operation to perform. The one exception is when the division is by a power of the radix of representation used. -Division by ten for example is simple for pencil and paper mathematics since it amounts to shifting the decimal place to the right. Similarly division -by two (\textit{or powers of two}) is very simple for binary computers to perform. It would therefore seem logical to choose $n$ of the form $2^p$ -which would imply that $\lfloor x / n \rfloor$ is a simple shift of $x$ right $p$ bits. - -However, there is one operation related to division of power of twos that is even faster than this. If $n = \beta^p$ then the division may be -performed by moving whole digits to the right $p$ places. In practice division by $\beta^p$ is much faster than division by $2^p$ for any $p$. -Also with the choice of $n = \beta^p$ reducing $x$ modulo $n$ requires zeroing the digits above the $p-1$'th digit of $x$. - -Throughout the next section the term ``restricted modulus'' will refer to a modulus of the form $\beta^p - k$ where as the term ``unrestricted -modulus'' will refer to a modulus of the form $2^p - k$. The word ``restricted'' in this case refers to the fact that it is based on the -$2^p$ logic except $p$ must be a multiple of $lg(\beta)$. - -\subsection{Choice of $k$} -Now that division and reduction (\textit{step 1 and 3 of figure~\ref{fig:DR}}) have been optimized to simple digit operations the multiplication by $k$ -in step 2 is the most expensive operation. Fortunately the choice of $k$ is not terribly limited. For all intents and purposes it might -as well be a single digit. The smaller the value of $k$ is the faster the algorithm will be. - -\subsection{Restricted Diminished Radix Reduction} -The restricted Diminished Radix algorithm can quickly reduce an input modulo a modulus of the form $n = \beta^p - k$. This algorithm can reduce -an input $x$ within the range $0 \le x < n^2$ using only a couple passes of the algorithm demonstrated in figure~\ref{fig:DR}. The implementation -of this algorithm has been optimized to avoid additional overhead associated with a division by $\beta^p$, the multiplication by $k$ or the addition -of $x$ and $q$. The resulting algorithm is very efficient and can lead to substantial improvements over Barrett and Montgomery reduction when modular -exponentiations are performed. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_dr\_reduce}. \\ -\textbf{Input}. mp\_int $x$, $n$ and a mp\_digit $k = \beta - n_0$ \\ -\hspace{11.5mm}($0 \le x < n^2$, $n > 1$, $0 < k < \beta$) \\ -\textbf{Output}. $x \mbox{ mod } n$ \\ -\hline \\ -1. $m \leftarrow n.used$ \\ -2. If $x.alloc < 2m$ then grow $x$ to $2m$ digits. \\ -3. $\mu \leftarrow 0$ \\ -4. for $i$ from $0$ to $m - 1$ do \\ -\hspace{3mm}4.1 $\hat r \leftarrow k \cdot x_{m+i} + x_{i} + \mu$ \\ -\hspace{3mm}4.2 $x_{i} \leftarrow \hat r \mbox{ (mod }\beta\mbox{)}$ \\ -\hspace{3mm}4.3 $\mu \leftarrow \lfloor \hat r / \beta \rfloor$ \\ -5. $x_{m} \leftarrow \mu$ \\ -6. for $i$ from $m + 1$ to $x.used - 1$ do \\ -\hspace{3mm}6.1 $x_{i} \leftarrow 0$ \\ -7. Clamp excess digits of $x$. \\ -8. If $x \ge n$ then \\ -\hspace{3mm}8.1 $x \leftarrow x - n$ \\ -\hspace{3mm}8.2 Goto step 3. \\ -9. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_dr\_reduce} -\end{figure} - -\textbf{Algorithm mp\_dr\_reduce.} -This algorithm will perform the Dimished Radix reduction of $x$ modulo $n$. It has similar restrictions to that of the Barrett reduction -with the addition that $n$ must be of the form $n = \beta^m - k$ where $0 < k <\beta$. - -This algorithm essentially implements the pseudo-code in figure~\ref{fig:DR} except with a slight optimization. The division by $\beta^m$, multiplication by $k$ -and addition of $x \mbox{ mod }\beta^m$ are all performed simultaneously inside the loop on step 4. The division by $\beta^m$ is emulated by accessing -the term at the $m+i$'th position which is subsequently multiplied by $k$ and added to the term at the $i$'th position. After the loop the $m$'th -digit is set to the carry and the upper digits are zeroed. Steps 5 and 6 emulate the reduction modulo $\beta^m$ that should have happend to -$x$ before the addition of the multiple of the upper half. - -At step 8 if $x$ is still larger than $n$ another pass of the algorithm is required. First $n$ is subtracted from $x$ and then the algorithm resumes -at step 3. - -\index{bn\_mp\_dr\_reduce.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_dr\_reduce.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* reduce "x" in place modulo "n" using the Diminished Radix algorithm. -018 * -019 * Based on algorithm from the paper -020 * -021 * "Generating Efficient Primes for Discrete Log Cryptosystems" -022 * Chae Hoon Lim, Pil Loong Lee, -023 * POSTECH Information Research Laboratories -024 * -025 * The modulus must be of a special format [see manual] -026 * -027 * Has been modified to use algorithm 7.10 from the LTM book instead -028 */ -029 int -030 mp_dr_reduce (mp_int * x, mp_int * n, mp_digit k) -031 \{ -032 int err, i, m; -033 mp_word r; -034 mp_digit mu, *tmpx1, *tmpx2; -035 -036 /* m = digits in modulus */ -037 m = n->used; -038 -039 /* ensure that "x" has at least 2m digits */ -040 if (x->alloc < m + m) \{ -041 if ((err = mp_grow (x, m + m)) != MP_OKAY) \{ -042 return err; -043 \} -044 \} -045 -046 /* top of loop, this is where the code resumes if -047 * another reduction pass is required. -048 */ -049 top: -050 /* aliases for digits */ -051 /* alias for lower half of x */ -052 tmpx1 = x->dp; -053 -054 /* alias for upper half of x, or x/B**m */ -055 tmpx2 = x->dp + m; -056 -057 /* set carry to zero */ -058 mu = 0; -059 -060 /* compute (x mod B**m) + mp * [x/B**m] inline and inplace */ -061 for (i = 0; i < m; i++) \{ -062 r = ((mp_word)*tmpx2++) * ((mp_word)k) + *tmpx1 + mu; -063 *tmpx1++ = r & MP_MASK; -064 mu = r >> ((mp_word)DIGIT_BIT); -065 \} -066 -067 /* set final carry */ -068 *tmpx1++ = mu; -069 -070 /* zero words above m */ -071 for (i = m + 1; i < x->used; i++) \{ -072 *tmpx1++ = 0; -073 \} -074 -075 /* clamp, sub and return */ -076 mp_clamp (x); -077 -078 /* if x >= n then subtract and reduce again -079 * Each successive "recursion" makes the input smaller and smaller. -080 */ -081 if (mp_cmp_mag (x, n) != MP_LT) \{ -082 s_mp_sub(x, n, x); -083 goto top; -084 \} -085 return MP_OKAY; -086 \} -\end{alltt} -\end{small} - -The first step is to grow $x$ as required to $2m$ digits since the reduction is performed in place on $x$. The label on line 49 is where -the algorithm will resume if further reduction passes are required. In theory it could be placed at the top of the function however, the size of -the modulus and question of whether $x$ is large enough are invariant after the first pass meaning that it would be a waste of time. - -The aliases $tmpx1$ and $tmpx2$ refer to the digits of $x$ where the latter is offset by $m$ digits. By reading digits from $x$ offset by $m$ digits -a division by $\beta^m$ can be simulated virtually for free. The loop on line 61 performs the bulk of the work (\textit{corresponds to step 4 of algorithm 7.11}) -in this algorithm. - -By line 68 the pointer $tmpx1$ points to the $m$'th digit of $x$ which is where the final carry will be placed. Similarly by line 71 the -same pointer will point to the $m+1$'th digit where the zeroes will be placed. - -Since the algorithm is only valid if both $x$ and $n$ are greater than zero an unsigned comparison suffices to determine if another pass is required. -With the same logic at line 82 the value of $x$ is known to be greater than or equal to $n$ meaning that an unsigned subtraction can be used -as well. Since the destination of the subtraction is the larger of the inputs the call to algorithm s\_mp\_sub cannot fail and the return code -does not need to be checked. - -\subsubsection{Setup} -To setup the restricted Diminished Radix algorithm the value $k = \beta - n_0$ is required. This algorithm is not really complicated but provided for -completeness. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_dr\_setup}. \\ -\textbf{Input}. mp\_int $n$ \\ -\textbf{Output}. $k = \beta - n_0$ \\ -\hline \\ -1. $k \leftarrow \beta - n_0$ \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_dr\_setup} -\end{figure} - -\index{bn\_mp\_dr\_setup.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_dr\_setup.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* determines the setup value */ -018 void mp_dr_setup(mp_int *a, mp_digit *d) -019 \{ -020 /* the casts are required if DIGIT_BIT is one less than -021 * the number of bits in a mp_digit [e.g. DIGIT_BIT==31] -022 */ -023 *d = (mp_digit)((((mp_word)1) << ((mp_word)DIGIT_BIT)) - -024 ((mp_word)a->dp[0])); -025 \} -026 -\end{alltt} -\end{small} - -\subsubsection{Modulus Detection} -Another algorithm which will be useful is the ability to detect a restricted Diminished Radix modulus. An integer is said to be -of restricted Diminished Radix form if all of the digits are equal to $\beta - 1$ except the trailing digit which may be any value. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_dr\_is\_modulus}. \\ -\textbf{Input}. mp\_int $n$ \\ -\textbf{Output}. $1$ if $n$ is in D.R form, $0$ otherwise \\ -\hline -1. If $n.used < 2$ then return($0$). \\ -2. for $ix$ from $1$ to $n.used - 1$ do \\ -\hspace{3mm}2.1 If $n_{ix} \ne \beta - 1$ return($0$). \\ -3. Return($1$). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_dr\_is\_modulus} -\end{figure} - -\textbf{Algorithm mp\_dr\_is\_modulus.} -This algorithm determines if a value is in Diminished Radix form. Step 1 rejects obvious cases where fewer than two digits are -in the mp\_int. Step 2 tests all but the first digit to see if they are equal to $\beta - 1$. If the algorithm manages to get to -step 3 then $n$ must of Diminished Radix form. - -\index{bn\_mp\_dr\_is\_modulus.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_dr\_is\_modulus.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* determines if a number is a valid DR modulus */ -018 int mp_dr_is_modulus(mp_int *a) -019 \{ -020 int ix; -021 -022 /* must be at least two digits */ -023 if (a->used < 2) \{ -024 return 0; -025 \} -026 -027 for (ix = 1; ix < a->used; ix++) \{ -028 if (a->dp[ix] != MP_MASK) \{ -029 return 0; -030 \} -031 \} -032 return 1; -033 \} -034 -\end{alltt} -\end{small} - -\subsection{Unrestricted Diminished Radix Reduction} -The unrestricted Diminished Radix algorithm allows modular reductions to be performed when the modulus is of the form $2^p - k$. This algorithm -is a straightforward adaptation of algorithm~\ref{fig:DR}. - -In general the restricted Diminished Radix reduction algorithm is much faster since it has considerably lower overhead. However, this new -algorithm is much faster than either Montgomery or Barrett reduction when the moduli are of the appropriate form. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_reduce\_2k}. \\ -\textbf{Input}. mp\_int $a$ and $n$. mp\_digit $k$ \\ -\hspace{11.5mm}($a \ge 0$, $n > 1$, $0 < k < \beta$, $n + k$ is a power of two) \\ -\textbf{Output}. $a \mbox{ (mod }n\mbox{)}$ \\ -\hline -1. $p \leftarrow \lceil lg(n) \rceil$ (\textit{mp\_count\_bits}) \\ -2. While $a \ge n$ do \\ -\hspace{3mm}2.1 $q \leftarrow \lfloor a / 2^p \rfloor$ (\textit{mp\_div\_2d}) \\ -\hspace{3mm}2.2 $a \leftarrow a \mbox{ (mod }2^p\mbox{)}$ (\textit{mp\_mod\_2d}) \\ -\hspace{3mm}2.3 $q \leftarrow q \cdot k$ (\textit{mp\_mul\_d}) \\ -\hspace{3mm}2.4 $a \leftarrow a - q$ (\textit{s\_mp\_sub}) \\ -\hspace{3mm}2.5 If $a \ge n$ then do \\ -\hspace{6mm}2.5.1 $a \leftarrow a - n$ \\ -3. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_reduce\_2k} -\end{figure} - -\textbf{Algorithm mp\_reduce\_2k.} -This algorithm quickly reduces an input $a$ modulo an unrestricted Diminished Radix modulus $n$. Division by $2^p$ is emulated with a right -shift which makes the algorithm fairly inexpensive to use. - -\index{bn\_mp\_reduce\_2k.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_reduce\_2k.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* reduces a modulo n where n is of the form 2**p - k */ -018 int -019 mp_reduce_2k(mp_int *a, mp_int *n, mp_digit k) -020 \{ -021 mp_int q; -022 int p, res; -023 -024 if ((res = mp_init(&q)) != MP_OKAY) \{ -025 return res; -026 \} -027 -028 p = mp_count_bits(n); -029 top: -030 /* q = a/2**p, a = a mod 2**p */ -031 if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) \{ -032 goto ERR; -033 \} -034 -035 if (k != 1) \{ -036 /* q = q * k */ -037 if ((res = mp_mul_d(&q, k, &q)) != MP_OKAY) \{ -038 goto ERR; -039 \} -040 \} -041 -042 /* a = a + q */ -043 if ((res = s_mp_add(a, &q, a)) != MP_OKAY) \{ -044 goto ERR; -045 \} -046 -047 if (mp_cmp_mag(a, n) != MP_LT) \{ -048 s_mp_sub(a, n, a); -049 goto top; -050 \} -051 -052 ERR: -053 mp_clear(&q); -054 return res; -055 \} -056 -\end{alltt} -\end{small} - -The algorithm mp\_count\_bits calculates the number of bits in an mp\_int which is used to find the initial value of $p$. The call to mp\_div\_2d -on line 31 calculates both the quotient $q$ and the remainder $a$ required. By doing both in a single function call the code size -is kept fairly small. The multiplication by $k$ is only performed if $k > 1$. This allows reductions modulo $2^p - 1$ to be performed without -any multiplications. - -The unsigned s\_mp\_add, mp\_cmp\_mag and s\_mp\_sub are used in place of their full sign counterparts since the inputs are only valid if they are -positive. By using the unsigned versions the overhead is kept to a minimum. - -\subsubsection{Unrestricted Setup} -To setup this reduction algorithm the value of $k = 2^p - n$ is required. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_reduce\_2k\_setup}. \\ -\textbf{Input}. mp\_int $n$ \\ -\textbf{Output}. $k = 2^p - n$ \\ -\hline -1. $p \leftarrow \lceil lg(n) \rceil$ (\textit{mp\_count\_bits}) \\ -2. $x \leftarrow 2^p$ (\textit{mp\_2expt}) \\ -3. $x \leftarrow x - n$ (\textit{mp\_sub}) \\ -4. $k \leftarrow x_0$ \\ -5. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_reduce\_2k\_setup} -\end{figure} - -\textbf{Algorithm mp\_reduce\_2k\_setup.} -This algorithm computes the value of $k$ required for the algorithm mp\_reduce\_2k. By making a temporary variable $x$ equal to $2^p$ a subtraction -is sufficient to solve for $k$. Alternatively if $n$ has more than one digit the value of $k$ is simply $\beta - n_0$. - -\index{bn\_mp\_reduce\_2k\_setup.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_reduce\_2k\_setup.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* determines the setup value */ -018 int -019 mp_reduce_2k_setup(mp_int *a, mp_digit *d) -020 \{ -021 int res, p; -022 mp_int tmp; -023 -024 if ((res = mp_init(&tmp)) != MP_OKAY) \{ -025 return res; -026 \} -027 -028 p = mp_count_bits(a); -029 if ((res = mp_2expt(&tmp, p)) != MP_OKAY) \{ -030 mp_clear(&tmp); -031 return res; -032 \} -033 -034 if ((res = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) \{ -035 mp_clear(&tmp); -036 return res; -037 \} -038 -039 *d = tmp.dp[0]; -040 mp_clear(&tmp); -041 return MP_OKAY; -042 \} -\end{alltt} -\end{small} - -\subsubsection{Unrestricted Detection} -An integer $n$ is a valid unrestricted Diminished Radix modulus if either of the following are true. - -\begin{enumerate} -\item The number has only one digit. -\item The number has more than one digit and every bit from the $\beta$'th to the most significant is one. -\end{enumerate} - -If either condition is true than there is a power of two namely $2^p$ such that $0 < 2^p - n < \beta$. If the input is only -one digit than it will always be of the correct form. Otherwise all of the bits above the first digit must be one. This arises from the fact -that there will be value of $k$ that when added to the modulus causes a carry in the first digit which propagates all the way to the most -significant bit. The resulting sum will be a power of two. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_reduce\_is\_2k}. \\ -\textbf{Input}. mp\_int $n$ \\ -\textbf{Output}. $1$ if of proper form, $0$ otherwise \\ -\hline -1. If $n.used = 0$ then return($0$). \\ -2. If $n.used = 1$ then return($1$). \\ -3. $p \leftarrow \rceil lg(n) \lceil$ (\textit{mp\_count\_bits}) \\ -4. for $x$ from $lg(\beta)$ to $p$ do \\ -\hspace{3mm}4.1 If the ($x \mbox{ mod }lg(\beta)$)'th bit of the $\lfloor x / lg(\beta) \rfloor$ of $n$ is zero then return($0$). \\ -5. Return($1$). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_reduce\_is\_2k} -\end{figure} - -\textbf{Algorithm mp\_reduce\_is\_2k.} -This algorithm quickly determines if a modulus is of the form required for algorithm mp\_reduce\_2k to function properly. - -\index{bn\_mp\_reduce\_is\_2k.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_reduce\_is\_2k.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* determines if mp_reduce_2k can be used */ -018 int -019 mp_reduce_is_2k(mp_int *a) -020 \{ -021 int ix, iy; -022 -023 if (a->used == 0) \{ -024 return 0; -025 \} else if (a->used == 1) \{ -026 return 1; -027 \} else if (a->used > 1) \{ -028 iy = mp_count_bits(a); -029 for (ix = DIGIT_BIT; ix < iy; ix++) \{ -030 if ((a->dp[ix/DIGIT_BIT] & -031 ((mp_digit)1 << (mp_digit)(ix % DIGIT_BIT))) == 0) \{ -032 return 0; -033 \} -034 \} -035 \} -036 return 1; -037 \} -038 -\end{alltt} -\end{small} - - - -\section{Algorithm Comparison} -So far three very different algorithms for modular reduction have been discussed. Each of the algorithms have their own strengths and weaknesses -that makes having such a selection very useful. The following table sumarizes the three algorithms along with comparisons of work factors. Since -all three algorithms have the restriction that $0 \le x < n^2$ and $n > 1$ those limitations are not included in the table. - -\begin{center} -\begin{small} -\begin{tabular}{|c|c|c|c|c|c|} -\hline \textbf{Method} & \textbf{Work Required} & \textbf{Limitations} & \textbf{$m = 8$} & \textbf{$m = 32$} & \textbf{$m = 64$} \\ -\hline Barrett & $m^2 + 2m - 1$ & None & $79$ & $1087$ & $4223$ \\ -\hline Montgomery & $m^2 + m$ & $n$ must be odd & $72$ & $1056$ & $4160$ \\ -\hline D.R. & $2m$ & $n = \beta^m - k$ & $16$ & $64$ & $128$ \\ -\hline -\end{tabular} -\end{small} -\end{center} - -In theory Montgomery and Barrett reductions would require roughly the same amount of time to complete. However, in practice since Montgomery -reduction can be written as a single function with the Comba technique it is much faster. Barrett reduction suffers from the overhead of -calling the half precision multipliers, addition and division by $\beta$ algorithms. - -For almost every cryptographic algorithm Montgomery reduction is the algorithm of choice. The one set of algorithms where Diminished Radix reduction truly -shines are based on the discrete logarithm problem such as Diffie-Hellman \cite{DH} and ElGamal \cite{ELGAMAL}. In these algorithms -primes of the form $\beta^m - k$ can be found and shared amongst users. These primes will allow the Diminished Radix algorithm to be used in -modular exponentiation to greatly speed up the operation. - - - -\section*{Exercises} -\begin{tabular}{cl} -$\left [ 3 \right ]$ & Prove that the ``trick'' in algorithm mp\_montgomery\_setup actually \\ - & calculates the correct value of $\rho$. \\ - & \\ -$\left [ 2 \right ]$ & Devise an algorithm to reduce modulo $n + k$ for small $k$ quickly. \\ - & \\ -$\left [ 4 \right ]$ & Prove that the pseudo-code algorithm ``Diminished Radix Reduction'' \\ - & (\textit{figure~\ref{fig:DR}}) terminates. Also prove the probability that it will \\ - & terminate within $1 \le k \le 10$ iterations. \\ - & \\ -\end{tabular} - - -\chapter{Exponentiation} -Exponentiation is the operation of raising one variable to the power of another, for example, $a^b$. A variant of exponentiation, computed -in a finite field or ring, is called modular exponentiation. This latter style of operation is typically used in public key -cryptosystems such as RSA and Diffie-Hellman. The ability to quickly compute modular exponentiations is of great benefit to any -such cryptosystem and many methods have been sought to speed it up. - -\section{Exponentiation Basics} -A trivial algorithm would simply multiply $a$ against itself $b - 1$ times to compute the exponentiation desired. However, as $b$ grows in size -the number of multiplications becomes prohibitive. Imagine what would happen if $b$ $\approx$ $2^{1024}$ as is the case when computing an RSA signature -with a $1024$-bit key. Such a calculation could never be completed as it would take simply far too long. - -Fortunately there is a very simple algorithm based on the laws of exponents. Recall that $lg_a(a^b) = b$ and that $lg_a(a^ba^c) = b + c$ which -are two trivial relationships between the base and the exponent. Let $b_i$ represent the $i$'th bit of $b$ starting from the least -significant bit. If $b$ is a $k$-bit integer than the following equation is true. - -\begin{equation} -a^b = \prod_{i=0}^{k-1} a^{2^i \cdot b_i} -\end{equation} - -By taking the base $a$ logarithm of both sides of the equation the following equation is the result. - -\begin{equation} -b = \sum_{i=0}^{k-1}2^i \cdot b_i -\end{equation} - -The term $a^{2^i}$ can be found from the $i - 1$'th term by squaring the term since $\left ( a^{2^i} \right )^2$ is equal to -$a^{2^{i+1}}$. This observation forms the basis of essentially all fast exponentiation algorithms. It requires $k$ squarings and on average -$k \over 2$ multiplications to compute the result. This is indeed quite an improvement over simply multiplying by $a$ a total of $b-1$ times. - -While this current method is a considerable speed up there are further improvements to be made. For example, the $a^{2^i}$ term does not need to -be computed in an auxilary variable. Consider the following equivalent algorithm. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{Left to Right Exponentiation}. \\ -\textbf{Input}. Integer $a$, $b$ and $k$ \\ -\textbf{Output}. $c = a^b$ \\ -\hline \\ -1. $c \leftarrow 1$ \\ -2. for $i$ from $k - 1$ to $0$ do \\ -\hspace{3mm}2.1 $c \leftarrow c^2$ \\ -\hspace{3mm}2.2 $c \leftarrow c \cdot a^{b_i}$ \\ -3. Return $c$. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Left to Right Exponentiation} -\label{fig:LTOR} -\end{figure} - -This algorithm starts from the most significant bit and works towards the least significant bit. When the $i$'th bit of $b$ is set $a$ is -multiplied against the current product. In each iteration the product is squared which doubles the exponent of the individual terms of the -product. - -For example, let $b = 101100_2 \equiv 44_{10}$. The following chart demonstrates the actions of the algorithm. - -\newpage\begin{figure} -\begin{center} -\begin{tabular}{|c|c|} -\hline \textbf{Value of $i$} & \textbf{Value of $c$} \\ -\hline - & $1$ \\ -\hline $5$ & $a$ \\ -\hline $4$ & $a^2$ \\ -\hline $3$ & $a^4 \cdot a$ \\ -\hline $2$ & $a^8 \cdot a^2 \cdot a$ \\ -\hline $1$ & $a^{16} \cdot a^4 \cdot a^2$ \\ -\hline $0$ & $a^{32} \cdot a^8 \cdot a^4$ \\ -\hline -\end{tabular} -\end{center} -\caption{Example of Left to Right Exponentiation} -\end{figure} - -When the product $a^{32} \cdot a^8 \cdot a^4$ is simplified it is equal $a^{44}$ which is the desired exponentiation. This particular algorithm is -called ``Left to Right'' because it reads the exponent in that order. All of the exponentiation algorithms that will be presented are of this nature. - -\subsection{Single Digit Exponentiation} -The first algorithm in the series of exponentiation algorithms will be an unbounded algorithm where the exponent is a single digit. It is intended -to be used when a small power of an input is required (\textit{e.g. $a^5$}). It is faster than simply multiplying $b - 1$ times for all values of -$b$ that are greater than three. - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_expt\_d}. \\ -\textbf{Input}. mp\_int $a$ and mp\_digit $b$ \\ -\textbf{Output}. $c = a^b$ \\ -\hline \\ -1. $g \leftarrow a$ (\textit{mp\_init\_copy}) \\ -2. $c \leftarrow 1$ (\textit{mp\_set}) \\ -3. for $x$ from 1 to $lg(\beta)$ do \\ -\hspace{3mm}3.1 $c \leftarrow c^2$ (\textit{mp\_sqr}) \\ -\hspace{3mm}3.2 If $b$ AND $2^{lg(\beta) - 1} \ne 0$ then \\ -\hspace{6mm}3.2.1 $c \leftarrow c \cdot g$ (\textit{mp\_mul}) \\ -\hspace{3mm}3.3 $b \leftarrow b << 1$ \\ -4. Clear $g$. \\ -5. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_expt\_d} -\end{figure} - -\textbf{Algorithm mp\_expt\_d.} -This algorithm computes the value of $a$ raised to the power of a single digit $b$. It uses the left to right exponentiation algorithm to -quickly compute the exponentiation. It is loosely based on algorithm 14.79 of HAC \cite[pp. 615]{HAC} with the difference that the -exponent is a fixed width. - -A copy of $a$ is made first to allow destination variable $c$ be the same as the source variable $a$. The result is set to the initial value of -$1$ in the subsequent step. - -Inside the loop the exponent is read from the most significant bit first down to the least significant bit. First $c$ is invariably squared -on step 3.1. In the following step if the most significant bit of $b$ is one the copy of $a$ is multiplied against $c$. The value -of $b$ is shifted left one bit to make the next bit down from the most signficant bit the new most significant bit. In effect each -iteration of the loop moves the bits of the exponent $b$ upwards to the most significant location. - -\index{bn\_mp\_expt\_d.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_expt\_d.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* calculate c = a**b using a square-multiply algorithm */ -018 int -019 mp_expt_d (mp_int * a, mp_digit b, mp_int * c) -020 \{ -021 int res, x; -022 mp_int g; -023 -024 if ((res = mp_init_copy (&g, a)) != MP_OKAY) \{ -025 return res; -026 \} -027 -028 /* set initial result */ -029 mp_set (c, 1); -030 -031 for (x = 0; x < (int) DIGIT_BIT; x++) \{ -032 /* square */ -033 if ((res = mp_sqr (c, c)) != MP_OKAY) \{ -034 mp_clear (&g); -035 return res; -036 \} -037 -038 /* if the bit is set multiply */ -039 if ((b & (mp_digit) (((mp_digit)1) << (DIGIT_BIT - 1))) != 0) \{ -040 if ((res = mp_mul (c, &g, c)) != MP_OKAY) \{ -041 mp_clear (&g); -042 return res; -043 \} -044 \} -045 -046 /* shift to next bit */ -047 b <<= 1; -048 \} -049 -050 mp_clear (&g); -051 return MP_OKAY; -052 \} -\end{alltt} -\end{small} - --- Some note later. - -\section{$k$-ary Exponentiation} -When calculating an exponentiation the most time consuming bottleneck is the multiplications which are in general a small factor -slower than squaring. Recall from the previous algorithm that $b_{i}$ refers to the $i$'th bit of the exponent $b$. Suppose instead it referred to -the $i$'th $k$-bit digit of the exponent of $b$. For $k = 1$ the definitions are synonymous and for $k > 1$ algorithm~\ref{fig:KARY} -computes the same exponentiation. A group of $k$ bits from the exponent is called a \textit{window}. That is it is a small window on only a -portion of the entire exponent. Consider the following modification to the basic left to right exponentiation algorithm. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{$k$-ary Exponentiation}. \\ -\textbf{Input}. Integer $a$, $b$, $k$ and $t$ \\ -\textbf{Output}. $c = a^b$ \\ -\hline \\ -1. $c \leftarrow 1$ \\ -2. for $i$ from $t - 1$ to $0$ do \\ -\hspace{3mm}2.1 $c \leftarrow c^{2^k} $ \\ -\hspace{3mm}2.2 Extract the $i$'th $k$-bit word from $b$ and store it in $g$. \\ -\hspace{3mm}2.3 $c \leftarrow c \cdot a^g$ \\ -3. Return $c$. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{$k$-ary Exponentiation} -\label{fig:KARY} -\end{figure} - -The squaring on step 2.1 can be calculated by squaring the value $c$ successively $k$ times. If the values of $a^g$ for $0 < g < 2^k$ have been -precomputed this algorithm requires only $t$ multiplications and $tk$ squarings. The table can be generated with $2^{k - 1} - 1$ squarings and -$2^{k - 1} + 1$ multiplications. This algorithm assumes that the number of bits in the exponent is evenly divisible by $k$. -However, when it is not the remaining $0 < x \le k - 1$ bits can be handled with algorithm~\ref{fig:LTOR}. - -Suppose $k = 4$ and $t = 100$. This modified algorithm will require $109$ multiplications and $408$ squarings to compute the exponentiation. The -original algorithm would on average have required $200$ multiplications and $400$ squrings to compute the same value. The total number of squarings -has increased slightly but the number of multiplications has nearly halved. - -\subsection{Optimal Values of $k$} -An optimal value of $k$ will minimize $2^{k} + \lceil n / k \rceil + n - 1$ for a fixed number of bits in the exponent $n$. The simplest -approach is to brute force search amongst the values $k = 2, 3, \ldots, 8$ for the lowest result. Table~\ref{fig:OPTK} lists optimal values of $k$ -for various exponent sizes and compares the number of multiplication and squarings required against algorithm~\ref{fig:LTOR}. - -\begin{figure}[here] -\begin{center} -\begin{small} -\begin{tabular}{|c|c|c|c|c|c|} -\hline \textbf{Exponent (bits)} & \textbf{Optimal $k$} & \textbf{Work at $k$} & \textbf{Work with ~\ref{fig:LTOR}} \\ -\hline $16$ & $2$ & $27$ & $24$ \\ -\hline $32$ & $3$ & $49$ & $48$ \\ -\hline $64$ & $3$ & $92$ & $96$ \\ -\hline $128$ & $4$ & $175$ & $192$ \\ -\hline $256$ & $4$ & $335$ & $384$ \\ -\hline $512$ & $5$ & $645$ & $768$ \\ -\hline $1024$ & $6$ & $1257$ & $1536$ \\ -\hline $2048$ & $6$ & $2452$ & $3072$ \\ -\hline $4096$ & $7$ & $4808$ & $6144$ \\ -\hline -\end{tabular} -\end{small} -\end{center} -\caption{Optimal Values of $k$ for $k$-ary Exponentiation} -\label{fig:OPTK} -\end{figure} - -\subsection{Sliding-Window Exponentiation} -A simple modification to the previous algorithm is only generate the upper half of the table in the range $2^{k-1} \le g < 2^k$. Essentially -this is a table for all values of $g$ where the most significant bit of $g$ is a one. However, in order for this to be allowed in the -algorithm values of $g$ in the range $0 \le g < 2^{k-1}$ must be avoided. - -Table~\ref{fig:OPTK2} lists optimal values of $k$ for various exponent sizes and compares the work required against algorithm~\ref{fig:KARY}. - -\begin{figure}[here] -\begin{center} -\begin{small} -\begin{tabular}{|c|c|c|c|c|c|} -\hline \textbf{Exponent (bits)} & \textbf{Optimal $k$} & \textbf{Work at $k$} & \textbf{Work with ~\ref{fig:KARY}} \\ -\hline $16$ & $3$ & $24$ & $27$ \\ -\hline $32$ & $3$ & $45$ & $49$ \\ -\hline $64$ & $4$ & $87$ & $92$ \\ -\hline $128$ & $4$ & $167$ & $175$ \\ -\hline $256$ & $5$ & $322$ & $335$ \\ -\hline $512$ & $6$ & $628$ & $645$ \\ -\hline $1024$ & $6$ & $1225$ & $1257$ \\ -\hline $2048$ & $7$ & $2403$ & $2452$ \\ -\hline $4096$ & $8$ & $4735$ & $4808$ \\ -\hline -\end{tabular} -\end{small} -\end{center} -\caption{Optimal Values of $k$ for Sliding Window Exponentiation} -\label{fig:OPTK2} -\end{figure} - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{Sliding Window $k$-ary Exponentiation}. \\ -\textbf{Input}. Integer $a$, $b$, $k$ and $t$ \\ -\textbf{Output}. $c = a^b$ \\ -\hline \\ -1. $c \leftarrow 1$ \\ -2. for $i$ from $t - 1$ to $0$ do \\ -\hspace{3mm}2.1 If the $i$'th bit of $b$ is a zero then \\ -\hspace{6mm}2.1.1 $c \leftarrow c^2$ \\ -\hspace{3mm}2.2 else do \\ -\hspace{6mm}2.2.1 $c \leftarrow c^{2^k}$ \\ -\hspace{6mm}2.2.2 Extract the $k$ bits from $(b_{i}b_{i-1}\ldots b_{i-(k-1)})$ and store it in $g$. \\ -\hspace{6mm}2.2.3 $c \leftarrow c \cdot a^g$ \\ -\hspace{6mm}2.2.4 $i \leftarrow i - k$ \\ -3. Return $c$. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Sliding Window $k$-ary Exponentiation} -\end{figure} - -Similar to the previous algorithm this algorithm must have a special handler when fewer than $k$ bits are left in the exponent. While this -algorithm requires the same number of squarings it can potentially have fewer multiplications. The pre-computed table $a^g$ is also half -the size as the previous table. - -Consider the exponent $b = 111101011001000_2 \equiv 31432_{10}$ with $k = 3$ using both algorithms. The first algorithm will divide the exponent up as -the following five $3$-bit words $b \equiv \left ( 111, 101, 011, 001, 000 \right )_{2}$. The second algorithm will break the -exponent as $b \equiv \left ( 111, 101, 0, 110, 0, 100, 0 \right )_{2}$. The single digit $0$ in the second representation are where -a single squaring took place instead of a squaring and multiplication. In total the first method requires $10$ multiplications and $18$ -squarings. The second method requires $8$ multiplications and $18$ squarings. - -In general the sliding window method is never slower than the generic $k$-ary method and often it is slightly faster. - -\section{Modular Exponentiation} - -Modular exponentiation is essentially computing the power of a base within a finite field or ring. For example, computing -$d \equiv a^b \mbox{ (mod }c\mbox{)}$ is a modular exponentiation. Instead of first computing $a^b$ and then reducing it -modulo $c$ the intermediate result is reduced modulo $c$ after every squaring or multiplication operation. - -This guarantees that any intermediate result is bounded by $0 \le d \le c^2 - 2c + 1$ and can be reduced modulo $c$ quickly using -one of the algorithms presented in chapter seven. - -Before the actual modular exponentiation algorithm can be written a wrapper algorithm must be written first. This algorithm -will allow the exponent $b$ to be negative which is computed as $c \equiv \left (1 / a \right )^{\vert b \vert} \mbox{(mod }d\mbox{)}$. The -value of $(1/a) \mbox{ mod }c$ is computed using the modular inverse (\textit{see section 10.4}). If no inverse exists the algorithm -terminates with an error. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_exptmod}. \\ -\textbf{Input}. mp\_int $a$, $b$ and $c$ \\ -\textbf{Output}. $y \equiv g^x \mbox{ (mod }p\mbox{)}$ \\ -\hline \\ -1. If $c.sign = MP\_NEG$ return(\textit{MP\_VAL}). \\ -2. If $b.sign = MP\_NEG$ then \\ -\hspace{3mm}2.1 $g' \leftarrow g^{-1} \mbox{ (mod }c\mbox{)}$ \\ -\hspace{3mm}2.2 $x' \leftarrow \vert x \vert$ \\ -\hspace{3mm}2.3 Compute $d \equiv g'^{x'} \mbox{ (mod }c\mbox{)}$ via recursion. \\ -3. if $p$ is odd \textbf{OR} $p$ is a D.R. modulus then \\ -\hspace{3mm}3.1 Compute $y \equiv g^{x} \mbox{ (mod }p\mbox{)}$ via algorithm mp\_exptmod\_fast. \\ -4. else \\ -\hspace{3mm}4.1 Compute $y \equiv g^{x} \mbox{ (mod }p\mbox{)}$ via algorithm s\_mp\_exptmod. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_exptmod} -\end{figure} - -\textbf{Algorithm mp\_exptmod.} -The first algorithm which actually performs modular exponentiation is algorithm s\_mp\_exptmod. It is a sliding window $k$-ary algorithm -which uses Barrett reduction to reduce the product modulo $p$. The second algorithm mp\_exptmod\_fast performs the same operation -except it uses either Montgomery or Diminished Radix reduction. The two latter reduction algorithms are clumped in the same exponentiation -algorithm since their arguments are essentially the same (\textit{two mp\_ints and one mp\_digit}). - -\index{bn\_mp\_exptmod.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_exptmod.c -\vspace{-3mm} -\begin{alltt} -016 -017 -018 /* this is a shell function that calls either the normal or Montgomery -019 * exptmod functions. Originally the call to the montgomery code was -020 * embedded in the normal function but that wasted alot of stack space -021 * for nothing (since 99% of the time the Montgomery code would be called) -022 */ -023 int -024 mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) -025 \{ -026 int dr; -027 -028 /* modulus P must be positive */ -029 if (P->sign == MP_NEG) \{ -030 return MP_VAL; -031 \} -032 -033 /* if exponent X is negative we have to recurse */ -034 if (X->sign == MP_NEG) \{ -035 mp_int tmpG, tmpX; -036 int err; -037 -038 /* first compute 1/G mod P */ -039 if ((err = mp_init(&tmpG)) != MP_OKAY) \{ -040 return err; -041 \} -042 if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) \{ -043 mp_clear(&tmpG); -044 return err; -045 \} -046 -047 /* now get |X| */ -048 if ((err = mp_init(&tmpX)) != MP_OKAY) \{ -049 mp_clear(&tmpG); -050 return err; -051 \} -052 if ((err = mp_abs(X, &tmpX)) != MP_OKAY) \{ -053 mp_clear_multi(&tmpG, &tmpX, NULL); -054 return err; -055 \} -056 -057 /* and now compute (1/G)**|X| instead of G**X [X < 0] */ -058 err = mp_exptmod(&tmpG, &tmpX, P, Y); -059 mp_clear_multi(&tmpG, &tmpX, NULL); -060 return err; -061 \} -062 -063 dr = mp_dr_is_modulus(P); -064 if (dr == 0) \{ -065 dr = mp_reduce_is_2k(P) << 1; -066 \} -067 -068 /* if the modulus is odd or dr != 0 use the fast method */ -069 if (mp_isodd (P) == 1 || dr != 0) \{ -070 return mp_exptmod_fast (G, X, P, Y, dr); -071 \} else \{ -072 return s_mp_exptmod (G, X, P, Y); -073 \} -074 \} -075 -\end{alltt} -\end{small} - -In order to keep the algorithms in a known state the first step on line 29 is to reject any negative modulus as input. If the exponent is -negative the algorithm tries to perform a modular exponentiation with the modular inverse of the base $G$. The temporary variable $tmpG$ is assigned -the modular inverse of $G$ and $tmpX$ is assigned the absolute value of $X$. The algorithm will recuse with these new values with a positive -exponent. - -If the exponent is positive the algorithm resumes the exponentiation. Line 63 determines if the modulus is of the restricted Diminished Radix -form. If it is not line 65 attempts to determine if it is of a unrestricted Diminished Radix form. The integer $dr$ will take on one -of three values. - -\begin{enumerate} -\item $dr = 0$ means that the modulus is not of either restricted or unrestricted Diminished Radix form. -\item $dr = 1$ means that the modulus is of restricted Diminished Radix form. -\item $dr = 2$ means that the modulus is of unrestricted Diminished Radix form. -\end{enumerate} - -Line 69 determines if the fast modular exponentiation algorithm can be used. It is allowed if $dr \ne 0$ or if the modulus is odd. Otherwise, -the slower s\_mp\_exptmod algorithm is used which uses Barrett reduction. - -\subsection{Barrett Modular Exponentiation} - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{s\_mp\_exptmod}. \\ -\textbf{Input}. mp\_int $a$, $b$ and $c$ \\ -\textbf{Output}. $y \equiv g^x \mbox{ (mod }p\mbox{)}$ \\ -\hline \\ -1. $k \leftarrow lg(x)$ \\ -2. $winsize \leftarrow \left \lbrace \begin{array}{ll} - 2 & \mbox{if }k \le 7 \\ - 3 & \mbox{if }7 < k \le 36 \\ - 4 & \mbox{if }36 < k \le 140 \\ - 5 & \mbox{if }140 < k \le 450 \\ - 6 & \mbox{if }450 < k \le 1303 \\ - 7 & \mbox{if }1303 < k \le 3529 \\ - 8 & \mbox{if }3529 < k \\ - \end{array} \right .$ \\ -3. Initialize $2^{winsize}$ mp\_ints in an array named $M$ and one mp\_int named $\mu$ \\ -4. Calculate the $\mu$ required for Barrett Reduction (\textit{mp\_reduce\_setup}). \\ -5. $M_1 \leftarrow g \mbox{ (mod }p\mbox{)}$ \\ -\\ -Setup the table of small powers of $g$. First find $g^{2^{winsize}}$ and then all multiples of it. \\ -6. $k \leftarrow 2^{winsize - 1}$ \\ -7. $M_{k} \leftarrow M_1$ \\ -8. for $ix$ from 0 to $winsize - 2$ do \\ -\hspace{3mm}8.1 $M_k \leftarrow \left ( M_k \right )^2$ (\textit{mp\_sqr}) \\ -\hspace{3mm}8.2 $M_k \leftarrow M_k \mbox{ (mod }p\mbox{)}$ (\textit{mp\_reduce}) \\ -9. for $ix$ from $2^{winsize - 1} + 1$ to $2^{winsize} - 1$ do \\ -\hspace{3mm}9.1 $M_{ix} \leftarrow M_{ix - 1} \cdot M_{1}$ (\textit{mp\_mul}) \\ -\hspace{3mm}9.2 $M_{ix} \leftarrow M_{ix} \mbox{ (mod }p\mbox{)}$ (\textit{mp\_reduce}) \\ -10. $res \leftarrow 1$ \\ -\\ -Start Sliding Window. \\ -11. $mode \leftarrow 0, bitcnt \leftarrow 1, buf \leftarrow 0, digidx \leftarrow x.used - 1, bitcpy \leftarrow 0, bitbuf \leftarrow 0$ \\ -12. Loop \\ -\hspace{3mm}12.1 $bitcnt \leftarrow bitcnt - 1$ \\ -\hspace{3mm}12.2 If $bitcnt = 0$ then do \\ -\hspace{6mm}12.2.1 If $digidx = -1$ goto step 13. \\ -\hspace{6mm}12.2.2 $buf \leftarrow x_{digidx}$ \\ -\hspace{6mm}12.2.3 $digidx \leftarrow digidx - 1$ \\ -\hspace{6mm}12.2.4 $bitcnt \leftarrow lg(\beta)$ \\ -Continued on next page. \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm s\_mp\_exptmod} -\end{figure} - -\newpage\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{s\_mp\_exptmod} (\textit{continued}). \\ -\textbf{Input}. mp\_int $a$, $b$ and $c$ \\ -\textbf{Output}. $y \equiv g^x \mbox{ (mod }p\mbox{)}$ \\ -\hline \\ -\hspace{3mm}12.3 $y \leftarrow (buf >> (lg(\beta) - 1))$ AND $1$ \\ -\hspace{3mm}12.4 $buf \leftarrow buf << 1$ \\ -\hspace{3mm}12.5 if $mode = 0$ and $y = 0$ then goto step 12. \\ -\hspace{3mm}12.6 if $mode = 1$ and $y = 0$ then do \\ -\hspace{6mm}12.6.1 $res \leftarrow res^2$ \\ -\hspace{6mm}12.6.2 $res \leftarrow res \mbox{ (mod }p\mbox{)}$ \\ -\hspace{6mm}12.6.3 Goto step 12. \\ -\hspace{3mm}12.7 $bitcpy \leftarrow bitcpy + 1$ \\ -\hspace{3mm}12.8 $bitbuf \leftarrow bitbuf + (y << (winsize - bitcpy))$ \\ -\hspace{3mm}12.9 $mode \leftarrow 2$ \\ -\hspace{3mm}12.10 If $bitcpy = winsize$ then do \\ -\hspace{6mm}Window is full so perform the squarings and single multiplication. \\ -\hspace{6mm}12.10.1 for $ix$ from $0$ to $winsize -1$ do \\ -\hspace{9mm}12.10.1.1 $res \leftarrow res^2$ \\ -\hspace{9mm}12.10.1.2 $res \leftarrow res \mbox{ (mod }p\mbox{)}$ \\ -\hspace{6mm}12.10.2 $res \leftarrow res \cdot M_{bitbuf}$ \\ -\hspace{6mm}12.10.3 $res \leftarrow res \mbox{ (mod }p\mbox{)}$ \\ -\hspace{6mm}Reset the window. \\ -\hspace{6mm}12.10.4 $bitcpy \leftarrow 0, bitbuf \leftarrow 0, mode \leftarrow 1$ \\ -\\ -No more windows left. Check for residual bits of exponent. \\ -13. If $mode = 2$ and $bitcpy > 0$ then do \\ -\hspace{3mm}13.1 for $ix$ form $0$ to $bitcpy - 1$ do \\ -\hspace{6mm}13.1.1 $res \leftarrow res^2$ \\ -\hspace{6mm}13.1.2 $res \leftarrow res \mbox{ (mod }p\mbox{)}$ \\ -\hspace{6mm}13.1.3 $bitbuf \leftarrow bitbuf << 1$ \\ -\hspace{6mm}13.1.4 If $bitbuf$ AND $2^{winsize} \ne 0$ then do \\ -\hspace{9mm}13.1.4.1 $res \leftarrow res \cdot M_{1}$ \\ -\hspace{9mm}13.1.4.2 $res \leftarrow res \mbox{ (mod }p\mbox{)}$ \\ -14. $y \leftarrow res$ \\ -15. Clear $res$, $mu$ and the $M$ array. \\ -16. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm s\_mp\_exptmod (continued)} -\end{figure} - -\textbf{Algorithm s\_mp\_exptmod.} -This algorithm computes the $x$'th power of $g$ modulo $p$ and stores the result in $y$. It takes advantage of the Barrett reduction -algorithm to keep the product small throughout the algorithm. - -The first two steps determine the optimal window size based on the number of bits in the exponent. The larger the exponent the -larger the window size becomes. After a window size $winsize$ has been chosen an array of $2^{winsize}$ mp\_int variables is allocated. This -table will hold the values of $g^x \mbox{ (mod }p\mbox{)}$ for $2^{winsize - 1} \le x < 2^{winsize}$. - -After the table is allocated the first power of $g$ is found. Since $g \ge p$ is allowed it must be first reduced modulo $p$ to make -the rest of the algorithm more efficient. The first element of the table at $2^{winsize - 1}$ is found by squaring $M_1$ successively $winsize - 2$ -times. The rest of the table elements are found by multiplying the previous element by $M_1$ modulo $p$. - -Now that the table is available the sliding window may begin. The following list describes the functions of all the variables in the window. -\begin{enumerate} -\item The variable $mode$ dictates how the bits of the exponent are interpreted. -\begin{enumerate} - \item When $mode = 0$ the bits are ignored since no non-zero bit of the exponent has been seen yet. For example, if the exponent were simply - $1$ then there would be $lg(\beta) - 1$ zero bits before the first non-zero bit. In this case bits are ignored until a non-zero bit is found. - \item When $mode = 1$ a non-zero bit has been seen before and a new $winsize$-bit window has not been formed yet. In this mode leading $0$ bits - are read and a single squaring is performed. If a non-zero bit is read a new window is created. - \item When $mode = 2$ the algorithm is in the middle of forming a window and new bits are appended to the window from the most significant bit - downwards. -\end{enumerate} -\item The variable $bitcnt$ indicates how many bits are left in the current digit of the exponent left to be read. When it reaches zero a new digit - is fetched from the exponent. -\item The variable $buf$ holds the currently read digit of the exponent. -\item The variable $digidx$ is an index into the exponents digits. It starts at the leading digit $x.used - 1$ and moves towards the trailing digit. -\item The variable $bitcpy$ indicates how many bits are in the currently formed window. When it reaches $winsize$ the window is flushed and - the appropriate operations performed. -\item The variable $bitbuf$ holds the current bits of the window being formed. -\end{enumerate} - -All of step 12 is the window processing loop. It will iterate while there are digits available form the exponent to read. The first step -inside this loop is to extract a new digit if no more bits are available in the current digit. If there are no bits left a new digit is -read and if there are no digits left than the loop terminates. - -After a digit is made available step 12.3 will extract the most significant bit of the current digit and move all other bits in the digit -upwards. In effect the digit is read from most significant bit to least significant bit and since the digits are read from leading to -trailing edges the entire exponent is read from most significant bit to least significant bit. - -At step 12.5 if the $mode$ and currently extracted bit $y$ are both zero the bit is ignored and the next bit is read. This prevents the -algorithm from having to perform trivial squaring and reduction operations before the first non-zero bit is read. Step 12.6 and 12.7-10 handle -the two cases of $mode = 1$ and $mode = 2$ respectively. - -\begin{center} -\begin{figure}[here] -\includegraphics{pics/expt_state} -\caption{Sliding Window State Diagram} -\end{figure} -\end{center} - -By step 13 there are no more digits left in the exponent. However, there may be partial bits in the window left. If $mode = 2$ then -a Left-to-Right algorithm is used to process the remaining few bits. - -\index{bn\_s\_mp\_exptmod.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_s\_mp\_exptmod.c -\vspace{-3mm} -\begin{alltt} -016 -017 int -018 s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) -019 \{ -020 mp_int M[256], res, mu; -021 mp_digit buf; -022 int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; -023 -024 /* find window size */ -025 x = mp_count_bits (X); -026 if (x <= 7) \{ -027 winsize = 2; -028 \} else if (x <= 36) \{ -029 winsize = 3; -030 \} else if (x <= 140) \{ -031 winsize = 4; -032 \} else if (x <= 450) \{ -033 winsize = 5; -034 \} else if (x <= 1303) \{ -035 winsize = 6; -036 \} else if (x <= 3529) \{ -037 winsize = 7; -038 \} else \{ -039 winsize = 8; -040 \} -041 -042 #ifdef MP_LOW_MEM -043 if (winsize > 5) \{ -044 winsize = 5; -045 \} -046 #endif -047 -048 /* init M array */ -049 for (x = 0; x < (1 << winsize); x++) \{ -050 if ((err = mp_init_size (&M[x], 1)) != MP_OKAY) \{ -051 for (y = 0; y < x; y++) \{ -052 mp_clear (&M[y]); -053 \} -054 return err; -055 \} -056 \} -057 -058 /* create mu, used for Barrett reduction */ -059 if ((err = mp_init (&mu)) != MP_OKAY) \{ -060 goto __M; -061 \} -062 if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) \{ -063 goto __MU; -064 \} -065 -066 /* create M table -067 * -068 * The M table contains powers of the base, -069 * e.g. M[x] = G**x mod P -070 * -071 * The first half of the table is not -072 * computed though accept for M[0] and M[1] -073 */ -074 if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) \{ -075 goto __MU; -076 \} -077 -078 /* compute the value at M[1<<(winsize-1)] by squaring -079 * M[1] (winsize-1) times -080 */ -081 if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) \{ -082 goto __MU; -083 \} -084 -085 for (x = 0; x < (winsize - 1); x++) \{ -086 if ((err = mp_sqr (&M[1 << (winsize - 1)], -087 &M[1 << (winsize - 1)])) != MP_OKAY) \{ -088 goto __MU; -089 \} -090 if ((err = mp_reduce (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) \{ -091 goto __MU; -092 \} -093 \} -094 -095 /* create upper table */ -096 for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) \{ -097 if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) \{ -098 goto __MU; -099 \} -100 if ((err = mp_reduce (&M[x], P, &mu)) != MP_OKAY) \{ -101 goto __MU; -102 \} -103 \} -104 -105 /* setup result */ -106 if ((err = mp_init (&res)) != MP_OKAY) \{ -107 goto __MU; -108 \} -109 mp_set (&res, 1); -110 -111 /* set initial mode and bit cnt */ -112 mode = 0; -113 bitcnt = 1; -114 buf = 0; -115 digidx = X->used - 1; -116 bitcpy = 0; -117 bitbuf = 0; -118 -119 for (;;) \{ -120 /* grab next digit as required */ -121 if (--bitcnt == 0) \{ -122 if (digidx == -1) \{ -123 break; -124 \} -125 buf = X->dp[digidx--]; -126 bitcnt = (int) DIGIT_BIT; -127 \} -128 -129 /* grab the next msb from the exponent */ -130 y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1; -131 buf <<= (mp_digit)1; -132 -133 /* if the bit is zero and mode == 0 then we ignore it -134 * These represent the leading zero bits before the first 1 bit -135 * in the exponent. Technically this opt is not required but it -136 * does lower the # of trivial squaring/reductions used -137 */ -138 if (mode == 0 && y == 0) -139 continue; -140 -141 /* if the bit is zero and mode == 1 then we square */ -142 if (mode == 1 && y == 0) \{ -143 if ((err = mp_sqr (&res, &res)) != MP_OKAY) \{ -144 goto __RES; -145 \} -146 if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) \{ -147 goto __RES; -148 \} -149 continue; -150 \} -151 -152 /* else we add it to the window */ -153 bitbuf |= (y << (winsize - ++bitcpy)); -154 mode = 2; -155 -156 if (bitcpy == winsize) \{ -157 /* ok window is filled so square as required and multiply */ -158 /* square first */ -159 for (x = 0; x < winsize; x++) \{ -160 if ((err = mp_sqr (&res, &res)) != MP_OKAY) \{ -161 goto __RES; -162 \} -163 if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) \{ -164 goto __RES; -165 \} -166 \} -167 -168 /* then multiply */ -169 if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) \{ -170 goto __MU; -171 \} -172 if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) \{ -173 goto __MU; -174 \} -175 -176 /* empty window and reset */ -177 bitcpy = 0; -178 bitbuf = 0; -179 mode = 1; -180 \} -181 \} -182 -183 /* if bits remain then square/multiply */ -184 if (mode == 2 && bitcpy > 0) \{ -185 /* square then multiply if the bit is set */ -186 for (x = 0; x < bitcpy; x++) \{ -187 if ((err = mp_sqr (&res, &res)) != MP_OKAY) \{ -188 goto __RES; -189 \} -190 if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) \{ -191 goto __RES; -192 \} -193 -194 bitbuf <<= 1; -195 if ((bitbuf & (1 << winsize)) != 0) \{ -196 /* then multiply */ -197 if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) \{ -198 goto __RES; -199 \} -200 if ((err = mp_reduce (&res, P, &mu)) != MP_OKAY) \{ -201 goto __RES; -202 \} -203 \} -204 \} -205 \} -206 -207 mp_exch (&res, Y); -208 err = MP_OKAY; -209 __RES:mp_clear (&res); -210 __MU:mp_clear (&mu); -211 __M: -212 for (x = 0; x < (1 << winsize); x++) \{ -213 mp_clear (&M[x]); -214 \} -215 return err; -216 \} -\end{alltt} -\end{small} - -Lines 26 through 40 determine the optimal window size based on the length of the exponent in bits. The window divisions are sorted -from smallest to greatest so that in each \textbf{if} statement only one condition must be tested. For example, by the \textbf{if} statement -on line 32 the value of $x$ is already known to be greater than $140$. - -The conditional piece of code beginning on line @42,define@ allows the window size to be restricted to five bits. This logic is used to ensure -the table of precomputed powers of $G$ remains relatively small. - -The for loop on line 49 initializes the $M$ array while lines 59 and 62 compute the value of $\mu$ required for -Barrett reduction. - --- More later. - -\section{Quick Power of Two} -Calculating $b = 2^a$ can be performed much quicker than with any of the previous algorithms. Recall that a logical shift left $m << k$ is -equivalent to $m \cdot 2^k$. By this logic when $m = 1$ a quick power of two can be achieved. - -\begin{figure}[!here] -\begin{small} -\begin{center} -\begin{tabular}{l} -\hline Algorithm \textbf{mp\_2expt}. \\ -\textbf{Input}. integer $b$ \\ -\textbf{Output}. $a \leftarrow 2^b$ \\ -\hline \\ -1. $a \leftarrow 0$ \\ -2. If $a.alloc < \lfloor b / lg(\beta) \rfloor + 1$ then grow $a$ appropriately. \\ -3. $a.used \leftarrow \lfloor b / lg(\beta) \rfloor + 1$ \\ -4. $a_{\lfloor b / lg(\beta) \rfloor} \leftarrow 1 << (b \mbox{ mod } lg(\beta))$ \\ -5. Return(\textit{MP\_OKAY}). \\ -\hline -\end{tabular} -\end{center} -\end{small} -\caption{Algorithm mp\_2expt} -\end{figure} - -\textbf{Algorithm mp\_2expt.} - -\index{bn\_mp\_2expt.c} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: bn\_mp\_2expt.c -\vspace{-3mm} -\begin{alltt} -016 -017 /* computes a = 2**b -018 * -019 * Simple algorithm which zeroes the int, grows it then just sets one bit -020 * as required. -021 */ -022 int -023 mp_2expt (mp_int * a, int b) -024 \{ -025 int res; -026 -027 mp_zero (a); -028 if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) \{ -029 return res; -030 \} -031 a->used = b / DIGIT_BIT + 1; -032 a->dp[b / DIGIT_BIT] = 1 << (b % DIGIT_BIT); -033 -034 return MP_OKAY; -035 \} -\end{alltt} -\end{small} - -\chapter{Higher Level Algorithms} - -This chapter discusses the various higher level algorithms that are required to complete a well rounded multiple precision integer package. These -routines are less performance oriented than the algorithms of chapters five, six and seven but are no less important. - -The first section describes a method of integer division with remainder that is universally well known. It provides the signed division logic -for the package. The subsequent section discusses a set of algorithms which allow a single digit to be the 2nd operand for a variety of operations. -These algorithms serve mostly to simplify other algorithms where small constants are required. The last two sections discuss how to manipulate -various representations of integers. For example, converting from an mp\_int to a string of character. - -\section{Integer Division with Remainder} - -Integer division aside from modular exponentiation is most intensive algorithm to compute. - - -\section{Single Digit Helpers} -\subsection{Single Digit Addition} -\subsection{Single Digit Subtraction} -\subsection{Single Digit Multiplication} -\subsection{Single Digit Division} -\subsection{Single Digit Modulo} -\subsection{Single Digit Root Extraction} -\section{Random Number Generation} -\section{Formatted Output} -\subsection{Getting The Output Size} -\subsection{Generating Radix-n Output} -\subsection{Reading Radix-n Input} -\section{Unformatted Output} -\subsection{Getting The Output Size} -\subsection{Generating Output} -\subsection{Reading Input} - -\chapter{Number Theoretic Algorithms} -\section{Greatest Common Divisor} -\section{Least Common Multiple} -\section{Jacobi Symbol Computation} -\section{Modular Inverse} -\subsection{General Case} -\subsection{Odd Moduli} -\section{Primality Tests} -\subsection{Trial Division} -\subsection{The Fermat Test} -\subsection{The Miller-Rabin Test} -\subsection{Primality Test in a Bottle} -\subsection{The Next Prime} -\section{Root Extraction} - -\backmatter -\appendix -\begin{thebibliography}{ABCDEF} -\bibitem[1]{TAOCPV2} -Donald Knuth, \textit{The Art of Computer Programming}, Third Edition, Volume Two, Seminumerical Algorithms, Addison-Wesley, 1998 - -\bibitem[2]{HAC} -A. Menezes, P. van Oorschot, S. Vanstone, \textit{Handbook of Applied Cryptography}, CRC Press, 1996 - -\bibitem[3]{ROSE} -Michael Rosing, \textit{Implementing Elliptic Curve Cryptography}, Manning Publications, 1999 - -\bibitem[4]{COMBA} -Paul G. Comba, \textit{Exponentiation Cryptosystems on the IBM PC}. IBM Systems Journal 29(4): 526-538 (1990) - -\bibitem[5]{KARA} -A. Karatsuba, Doklay Akad. Nauk SSSR 145 (1962), pp.293-294 - -\bibitem[6]{KARAP} -Andre Weimerskirch and Christof Paar, \textit{Generalizations of the Karatsuba Algorithm for Polynomial Multiplication}, Submitted to Design, Codes and Cryptography, March 2002 - -\bibitem[7]{BARRETT} -Paul Barrett, \textit{Implementing the Rivest Shamir and Adleman Public Key Encryption Algorithm on a Standard Digital Signal Processor}, Advances in Cryptology, Crypto '86, Springer-Verlag. - -\bibitem[8]{MONT} -P.L.Montgomery. \textit{Modular multiplication without trial division}. Mathematics of Computation, 44(170):519-521, April 1985. - -\bibitem[9]{DRMET} -Chae Hoon Lim and Pil Joong Lee, \textit{Generating Efficient Primes for Discrete Log Cryptosystems}, POSTECH Information Research Laboratories - -\bibitem[10]{MMB} -J. Daemen and R. Govaerts and J. Vandewalle, \textit{Block ciphers based on Modular Arithmetic}, State and {P}rogress in the {R}esearch of {C}ryptography, 1993, pp. 80-89 - -\end{thebibliography} - -\input{tommath.ind} - -\chapter{Appendix} -\subsection*{Appendix A -- Source Listing of tommath.h} - -The following is the source listing of the header file ``tommath.h'' for the LibTomMath project. It contains many of -the definitions used throughout the code such as \textbf{mp\_int}, \textbf{MP\_PREC} and so on. The header is -presented here for completeness. - -\index{tommath.h} -\vspace{+3mm}\begin{small} -\hspace{-5.1mm}{\bf File}: tommath.h -\vspace{-3mm} -\begin{alltt} -001 /* LibTomMath, multiple-precision integer library -- Tom St Denis -002 * -003 * LibTomMath is library that provides for multiple-precision -004 * integer arithmetic as well as number theoretic functionality. -005 * -006 * The library is designed directly after the MPI library by -007 * Michael Fromberger but has been written from scratch with -008 * additional optimizations in place. -009 * -010 * The library is free for all purposes without any express -011 * guarantee it works. -012 * -013 * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org -014 */ -015 #ifndef BN_H_ -016 #define BN_H_ -017 -018 #include -019 #include -020 #include -021 #include -022 #include -023 -024 #undef MIN -025 #define MIN(x,y) ((x)<(y)?(x):(y)) -026 #undef MAX -027 #define MAX(x,y) ((x)>(y)?(x):(y)) -028 -029 #ifdef __cplusplus -030 extern "C" \{ -031 -032 /* C++ compilers don't like assigning void * to mp_digit * */ -033 #define OPT_CAST (mp_digit *) -034 -035 #else -036 -037 /* C on the other hand doesn't care */ -038 #define OPT_CAST -039 -040 #endif -041 -042 /* some default configurations. -043 * -044 * A "mp_digit" must be able to hold DIGIT_BIT + 1 bits -045 * A "mp_word" must be able to hold 2*DIGIT_BIT + 1 bits -046 * -047 * At the very least a mp_digit must be able to hold 7 bits -048 * [any size beyond that is ok provided it doesn't overflow the data type] -049 */ -050 #ifdef MP_8BIT -051 typedef unsigned char mp_digit; -052 typedef unsigned short mp_word; -053 #elif defined(MP_16BIT) -054 typedef unsigned short mp_digit; -055 typedef unsigned long mp_word; -056 #elif defined(MP_64BIT) -057 /* for GCC only on supported platforms */ -058 #ifndef CRYPT -059 typedef unsigned long long ulong64; -060 typedef signed long long long64; -061 #endif -062 -063 typedef ulong64 mp_digit; -064 typedef unsigned long mp_word __attribute__ ((mode(TI))); -065 -066 #define DIGIT_BIT 60 -067 #else -068 /* this is the default case, 28-bit digits */ -069 -070 /* this is to make porting into LibTomCrypt easier :-) */ -071 #ifndef CRYPT -072 #if defined(_MSC_VER) || defined(__BORLANDC__) -073 typedef unsigned __int64 ulong64; -074 typedef signed __int64 long64; -075 #else -076 typedef unsigned long long ulong64; -077 typedef signed long long long64; -078 #endif -079 #endif -080 -081 typedef unsigned long mp_digit; -082 typedef ulong64 mp_word; -083 -084 #ifdef MP_31BIT -085 #define DIGIT_BIT 31 -086 #else -087 #define DIGIT_BIT 28 -088 #endif -089 #endif -090 -091 /* otherwise the bits per digit is calculated automatically from the size of - a mp_digit */ -092 #ifndef DIGIT_BIT -093 #define DIGIT_BIT ((CHAR_BIT * sizeof(mp_digit) - 1)) /* bits per di - git */ -094 #endif -095 -096 -097 #define MP_DIGIT_BIT DIGIT_BIT -098 #define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit) - 1)) -099 #define MP_DIGIT_MAX MP_MASK -100 -101 /* equalities */ -102 #define MP_LT -1 /* less than */ -103 #define MP_EQ 0 /* equal to */ -104 #define MP_GT 1 /* greater than */ -105 -106 #define MP_ZPOS 0 /* positive integer */ -107 #define MP_NEG 1 /* negative */ -108 -109 #define MP_OKAY 0 /* ok result */ -110 #define MP_MEM -2 /* out of mem */ -111 #define MP_VAL -3 /* invalid input */ -112 #define MP_RANGE MP_VAL -113 -114 typedef int mp_err; -115 -116 /* you'll have to tune these... */ -117 extern int KARATSUBA_MUL_CUTOFF, -118 KARATSUBA_SQR_CUTOFF, -119 TOOM_MUL_CUTOFF, -120 TOOM_SQR_CUTOFF; -121 -122 /* various build options */ -123 #define MP_PREC 64 /* default digits of precision (must - be power of two) */ -124 -125 /* define this to use lower memory usage routines (exptmods mostly) */ -126 /* #define MP_LOW_MEM */ -127 -128 /* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER - _DIGIT*2) */ -129 #define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGI - T_BIT + 1)) -130 -131 typedef struct \{ -132 int used, alloc, sign; -133 mp_digit *dp; -134 \} mp_int; -135 -136 #define USED(m) ((m)->used) -137 #define DIGIT(m,k) ((m)->dp[k]) -138 #define SIGN(m) ((m)->sign) -139 -140 /* ---> init and deinit bignum functions <--- */ -141 -142 /* init a bignum */ -143 int mp_init(mp_int *a); -144 -145 /* free a bignum */ -146 void mp_clear(mp_int *a); -147 -148 /* init a null terminated series of arguments */ -149 int mp_init_multi(mp_int *mp, ...); -150 -151 /* clear a null terminated series of arguments */ -152 void mp_clear_multi(mp_int *mp, ...); -153 -154 /* exchange two ints */ -155 void mp_exch(mp_int *a, mp_int *b); -156 -157 /* shrink ram required for a bignum */ -158 int mp_shrink(mp_int *a); -159 -160 /* grow an int to a given size */ -161 int mp_grow(mp_int *a, int size); -162 -163 /* init to a given number of digits */ -164 int mp_init_size(mp_int *a, int size); -165 -166 /* ---> Basic Manipulations <--- */ -167 -168 #define mp_iszero(a) (((a)->used == 0) ? 1 : 0) -169 #define mp_iseven(a) (((a)->used == 0 || (((a)->dp[0] & 1) == 0)) ? 1 : 0) -170 #define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? 1 : 0) -171 -172 /* set to zero */ -173 void mp_zero(mp_int *a); -174 -175 /* set to a digit */ -176 void mp_set(mp_int *a, mp_digit b); -177 -178 /* set a 32-bit const */ -179 int mp_set_int(mp_int *a, unsigned int b); -180 -181 /* copy, b = a */ -182 int mp_copy(mp_int *a, mp_int *b); -183 -184 /* inits and copies, a = b */ -185 int mp_init_copy(mp_int *a, mp_int *b); -186 -187 /* trim unused digits */ -188 void mp_clamp(mp_int *a); -189 -190 /* ---> digit manipulation <--- */ -191 -192 /* right shift by "b" digits */ -193 void mp_rshd(mp_int *a, int b); -194 -195 /* left shift by "b" digits */ -196 int mp_lshd(mp_int *a, int b); -197 -198 /* c = a / 2**b */ -199 int mp_div_2d(mp_int *a, int b, mp_int *c, mp_int *d); -200 -201 /* b = a/2 */ -202 int mp_div_2(mp_int *a, mp_int *b); -203 -204 /* c = a * 2**b */ -205 int mp_mul_2d(mp_int *a, int b, mp_int *c); -206 -207 /* b = a*2 */ -208 int mp_mul_2(mp_int *a, mp_int *b); -209 -210 /* c = a mod 2**d */ -211 int mp_mod_2d(mp_int *a, int b, mp_int *c); -212 -213 /* computes a = 2**b */ -214 int mp_2expt(mp_int *a, int b); -215 -216 /* makes a pseudo-random int of a given size */ -217 int mp_rand(mp_int *a, int digits); -218 -219 /* ---> binary operations <--- */ -220 /* c = a XOR b */ -221 int mp_xor(mp_int *a, mp_int *b, mp_int *c); -222 -223 /* c = a OR b */ -224 int mp_or(mp_int *a, mp_int *b, mp_int *c); -225 -226 /* c = a AND b */ -227 int mp_and(mp_int *a, mp_int *b, mp_int *c); -228 -229 /* ---> Basic arithmetic <--- */ -230 -231 /* b = -a */ -232 int mp_neg(mp_int *a, mp_int *b); -233 -234 /* b = |a| */ -235 int mp_abs(mp_int *a, mp_int *b); -236 -237 /* compare a to b */ -238 int mp_cmp(mp_int *a, mp_int *b); -239 -240 /* compare |a| to |b| */ -241 int mp_cmp_mag(mp_int *a, mp_int *b); -242 -243 /* c = a + b */ -244 int mp_add(mp_int *a, mp_int *b, mp_int *c); -245 -246 /* c = a - b */ -247 int mp_sub(mp_int *a, mp_int *b, mp_int *c); -248 -249 /* c = a * b */ -250 int mp_mul(mp_int *a, mp_int *b, mp_int *c); -251 -252 /* b = a*a */ -253 int mp_sqr(mp_int *a, mp_int *b); -254 -255 /* a/b => cb + d == a */ -256 int mp_div(mp_int *a, mp_int *b, mp_int *c, mp_int *d); -257 -258 /* c = a mod b, 0 <= c < b */ -259 int mp_mod(mp_int *a, mp_int *b, mp_int *c); -260 -261 /* ---> single digit functions <--- */ -262 -263 /* compare against a single digit */ -264 int mp_cmp_d(mp_int *a, mp_digit b); -265 -266 /* c = a + b */ -267 int mp_add_d(mp_int *a, mp_digit b, mp_int *c); -268 -269 /* c = a - b */ -270 int mp_sub_d(mp_int *a, mp_digit b, mp_int *c); -271 -272 /* c = a * b */ -273 int mp_mul_d(mp_int *a, mp_digit b, mp_int *c); -274 -275 /* a/b => cb + d == a */ -276 int mp_div_d(mp_int *a, mp_digit b, mp_int *c, mp_digit *d); -277 -278 /* a/3 => 3c + d == a */ -279 int mp_div_3(mp_int *a, mp_int *c, mp_digit *d); -280 -281 /* c = a**b */ -282 int mp_expt_d(mp_int *a, mp_digit b, mp_int *c); -283 -284 /* c = a mod b, 0 <= c < b */ -285 int mp_mod_d(mp_int *a, mp_digit b, mp_digit *c); -286 -287 /* ---> number theory <--- */ -288 -289 /* d = a + b (mod c) */ -290 int mp_addmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); -291 -292 /* d = a - b (mod c) */ -293 int mp_submod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); -294 -295 /* d = a * b (mod c) */ -296 int mp_mulmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); -297 -298 /* c = a * a (mod b) */ -299 int mp_sqrmod(mp_int *a, mp_int *b, mp_int *c); -300 -301 /* c = 1/a (mod b) */ -302 int mp_invmod(mp_int *a, mp_int *b, mp_int *c); -303 -304 /* c = (a, b) */ -305 int mp_gcd(mp_int *a, mp_int *b, mp_int *c); -306 -307 /* c = [a, b] or (a*b)/(a, b) */ -308 int mp_lcm(mp_int *a, mp_int *b, mp_int *c); -309 -310 /* finds one of the b'th root of a, such that |c|**b <= |a| -311 * -312 * returns error if a < 0 and b is even -313 */ -314 int mp_n_root(mp_int *a, mp_digit b, mp_int *c); -315 -316 /* shortcut for square root */ -317 #define mp_sqrt(a, b) mp_n_root(a, 2, b) -318 -319 /* computes the jacobi c = (a | n) (or Legendre if b is prime) */ -320 int mp_jacobi(mp_int *a, mp_int *n, int *c); -321 -322 /* used to setup the Barrett reduction for a given modulus b */ -323 int mp_reduce_setup(mp_int *a, mp_int *b); -324 -325 /* Barrett Reduction, computes a (mod b) with a precomputed value c -326 * -327 * Assumes that 0 < a <= b*b, note if 0 > a > -(b*b) then you can merely -328 * compute the reduction as -1 * mp_reduce(mp_abs(a)) [pseudo code]. -329 */ -330 int mp_reduce(mp_int *a, mp_int *b, mp_int *c); -331 -332 /* setups the montgomery reduction */ -333 int mp_montgomery_setup(mp_int *a, mp_digit *mp); -334 -335 /* computes a = B**n mod b without division or multiplication useful for -336 * normalizing numbers in a Montgomery system. -337 */ -338 int mp_montgomery_calc_normalization(mp_int *a, mp_int *b); -339 -340 /* computes x/R == x (mod N) via Montgomery Reduction */ -341 int mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp); -342 -343 /* returns 1 if a is a valid DR modulus */ -344 int mp_dr_is_modulus(mp_int *a); -345 -346 /* sets the value of "d" required for mp_dr_reduce */ -347 void mp_dr_setup(mp_int *a, mp_digit *d); -348 -349 /* reduces a modulo b using the Diminished Radix method */ -350 int mp_dr_reduce(mp_int *a, mp_int *b, mp_digit mp); -351 -352 /* returns true if a can be reduced with mp_reduce_2k */ -353 int mp_reduce_is_2k(mp_int *a); -354 -355 /* determines k value for 2k reduction */ -356 int mp_reduce_2k_setup(mp_int *a, mp_digit *d); -357 -358 /* reduces a modulo b where b is of the form 2**p - k [0 <= a] */ -359 int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit k); -360 -361 /* d = a**b (mod c) */ -362 int mp_exptmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d); -363 -364 /* ---> Primes <--- */ -365 -366 /* number of primes */ -367 #ifdef MP_8BIT -368 #define PRIME_SIZE 31 -369 #else -370 #define PRIME_SIZE 256 -371 #endif -372 -373 /* table of first PRIME_SIZE primes */ -374 extern const mp_digit __prime_tab[]; -375 -376 /* result=1 if a is divisible by one of the first PRIME_SIZE primes */ -377 int mp_prime_is_divisible(mp_int *a, int *result); -378 -379 /* performs one Fermat test of "a" using base "b". -380 * Sets result to 0 if composite or 1 if probable prime -381 */ -382 int mp_prime_fermat(mp_int *a, mp_int *b, int *result); -383 -384 /* performs one Miller-Rabin test of "a" using base "b". -385 * Sets result to 0 if composite or 1 if probable prime -386 */ -387 int mp_prime_miller_rabin(mp_int *a, mp_int *b, int *result); -388 -389 /* performs t rounds of Miller-Rabin on "a" using the first -390 * t prime bases. Also performs an initial sieve of trial -391 * division. Determines if "a" is prime with probability -392 * of error no more than (1/4)**t. -393 * -394 * Sets result to 1 if probably prime, 0 otherwise -395 */ -396 int mp_prime_is_prime(mp_int *a, int t, int *result); -397 -398 /* finds the next prime after the number "a" using "t" trials -399 * of Miller-Rabin. -400 */ -401 int mp_prime_next_prime(mp_int *a, int t); -402 -403 -404 /* ---> radix conversion <--- */ -405 int mp_count_bits(mp_int *a); -406 -407 int mp_unsigned_bin_size(mp_int *a); -408 int mp_read_unsigned_bin(mp_int *a, unsigned char *b, int c); -409 int mp_to_unsigned_bin(mp_int *a, unsigned char *b); -410 -411 int mp_signed_bin_size(mp_int *a); -412 int mp_read_signed_bin(mp_int *a, unsigned char *b, int c); -413 int mp_to_signed_bin(mp_int *a, unsigned char *b); -414 -415 int mp_read_radix(mp_int *a, char *str, int radix); -416 int mp_toradix(mp_int *a, char *str, int radix); -417 int mp_radix_size(mp_int *a, int radix); -418 -419 int mp_fread(mp_int *a, int radix, FILE *stream); -420 int mp_fwrite(mp_int *a, int radix, FILE *stream); -421 -422 #define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len)) -423 #define mp_raw_size(mp) mp_signed_bin_size(mp) -424 #define mp_toraw(mp, str) mp_to_signed_bin((mp), (str)) -425 #define mp_read_mag(mp, str, len) mp_read_unsigned_bin((mp), (str), (len)) -426 #define mp_mag_size(mp) mp_unsigned_bin_size(mp) -427 #define mp_tomag(mp, str) mp_to_unsigned_bin((mp), (str)) -428 -429 #define mp_tobinary(M, S) mp_toradix((M), (S), 2) -430 #define mp_tooctal(M, S) mp_toradix((M), (S), 8) -431 #define mp_todecimal(M, S) mp_toradix((M), (S), 10) -432 #define mp_tohex(M, S) mp_toradix((M), (S), 16) -433 -434 /* lowlevel functions, do not call! */ -435 int s_mp_add(mp_int *a, mp_int *b, mp_int *c); -436 int s_mp_sub(mp_int *a, mp_int *b, mp_int *c); -437 #define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1) -438 int fast_s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs); -439 int s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs); -440 int fast_s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs); -441 int s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs); -442 int fast_s_mp_sqr(mp_int *a, mp_int *b); -443 int s_mp_sqr(mp_int *a, mp_int *b); -444 int mp_karatsuba_mul(mp_int *a, mp_int *b, mp_int *c); -445 int mp_toom_mul(mp_int *a, mp_int *b, mp_int *c); -446 int mp_karatsuba_sqr(mp_int *a, mp_int *b); -447 int mp_toom_sqr(mp_int *a, mp_int *b); -448 int fast_mp_invmod(mp_int *a, mp_int *b, mp_int *c); -449 int fast_mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp); -450 int mp_exptmod_fast(mp_int *G, mp_int *X, mp_int *P, mp_int *Y, int mode); -451 int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y); -452 void bn_reverse(unsigned char *s, int len); -453 -454 #ifdef __cplusplus -455 \} -456 #endif -457 -458 #endif -459 -\end{alltt} -\end{small} - -\end{document} \ No newline at end of file