天天看點

第二十三個知識點:寫一個實作蒙哥馬利算法的C程式

第二十三個知識點:寫一個實作蒙哥馬利算法的C程式

這次部落格我将通過對蒙哥馬利算法的一個實際的實作,來補充我們上周蒙哥馬利算法的理論方面。這個用C語言實作的蒙哥馬利算法,是為一個位數為64的計算機編寫的。模數\(m\)是以能和\(2^{64}-1\)一樣大,\(a\)和\(b\)能和\(m-1\)一樣大。我們采用\(r = 2^{64}\)。在之前的部落格裡,給出的大部分資訊都來自于[1],是以請參考這裡的資訊。

在讀過上次部落格後,你知道我們需要四個步驟。為了我們的目的,我們将這些分為三個階段。

1.The GCD Operation

這個函數用了二進制擴充歐幾裡得算法,找出一個\(r^{-1}\)和\(m^{'}\)使得\(rr^{-1} = 1 + mm^{'}\)。這些整數在後面的算法中需要使用到。算法用\(r^{-1}\)和\(m^{'}\)計算出\(m,m^{'}\),這個部落格的目的不是介紹這個二進制擴充歐幾裡得算法。你想知道的更多可以看連結[1]和[2]。

2.Transform the Multipliers

第二階段是計算兩個值\(abar = ar \mod m\)和\(bbar = br \mod m\).因為\(r = 2^{64}\),這裡隻需要右移64位。就是輸出128位,前64位是\(a,b\)的值,後64位都是0。然後計算\(m\)的模數。這個函數接受64位的\(x\),同時接受低64位的\(y\)和一個\(m\)的值。之後傳回一個64位的值。

uint64 modul64(uint64 x, uint64 y, uint64 z);

uint64

是這樣定義的:

typedef unsigned long long uint64;

3.Montgomery Multiplication

這個函數定義成接受64位的abar,bbar,m和mprime。然後傳回64位的值。

首先計算\(t = abar*bbar\)。這個得到一個128位的整數。

然後計算\(u = (t + ( tm^{'} \mod r)*m)/r\)。\(t\)是一個128位的整數。這裡就可以計算了。定義如下:

tm = tlo*mprime;
mulul64(tm,m,&tmmhi,%tmmlo);
           

然後計算:

ulo = tlo + tmmlo;
uhi = thi + tmmhi;
if (ulo < tlo) uhi = uhi +1; // test for overflow from ulo and add if necessary to uhi
ov = (uhi < thi) | ((uhi == thi) & (ulo < tlo)); // check for carry
           

最後一步約減到\(m\)。

ulo = uhi;
uhi = 0;
if(ov > 0 || ulo >= m) // test if there was overflow or ulo is higher that
             ulo = ulo – m;
return ulo;
           

4.The Inverse Transformation

最後計算\(a*b \mod m = ur^{-1} \mod m\)

調用之前的函數。

mulul64(p, rinv, &phi, &plo); // performs multiplication and returns two 64 bit values phi and plo
p = modul64(phi, plo, m); // returns value of 128bit input mod m
           

這裡\(p\)就是蒙哥馬利算法的結果了。

[1] http://www.hackersdelight.org/MontgomeryMultiplication.pdf

[2] http://www.ucl.ac.uk/~ucahcjm/combopt/ext_gcd_python_programs.pdf