有限体の実装3(Montgomery乗算の紹介)
初めに
今回は有限体の山場、Montgomery乗算を紹介します。
Montgomery乗算は普通の乗算の代わりとなる重要な演算です。最初にMontgomery乗算のPythonコードを紹介し、それが持つ数学的な性質を考察します。
記事全体の一覧は有限体の実装一覧参照。
Montgomery乗算
素数
しかし
しばらく数学的な話が続きます。まずいくつか記号の準備をします。
次のコードで示す関数 mont(x, y) をMontgomery乗算と呼ぶことにします。
もっと簡潔に記述できる部分もありますが、C/C++で実装しやすいようにやや冗長に書いています。コード中のipはp'と読み替えてください。
def mont(x, y):
MASK = 2**L - 1
t = 0
for i in range(N):
t += x * ((y >> (L * i)) & MASK) # (A)
q = ((t & MASK) * self.ip) & MASK # (B)
t += q * self.p # (C)
t >>= L # (D)
if t >= self.p: # (E)
t -= self.p
return t
コードの説明をしましょう。
(A)
x, yがN桁のuint64_t
の配列とすると (y >> (L * i)) & MASK
は y[i]
を表します。
つまりC++なら x * y[i]
をmulUnitを使って計算し、tに足します。
(B)
(A)で計算したtの下位64ビットにp'(=ip)を掛けてその下位64ビットをqとします。
p'もuint64_tなのでここは
uint64_t q = t[0] * ip;
と同じです。
(C)
mulUnit
を使って p と q を掛けて t に足します。
(D)
t を 64ビット右シフトします。
(E)
ループを抜けたら t が p より大きければ p を引いて値を返します。
Montgomery乗算の意味
さて、mont(x, y)が数学的に何をしているか考察しましょう。
定理 : mont(x, y) =
{}\bmod{p} で一致することの証明
まず準備として整数
さてPythonのコードに戻ります。
最初 t = 0 で (A)から(D)まで実行すると
次のループでは
これを
(E)を実行するだけで両辺が一致することの証明
最後に mont(x, y) が
i回目のループのときにステップ(A)に入る直前は
- (仮定)
。t \le 2p-1 - (A)の右辺の最大値は
なので(p-1)(M-1) 。t \le 2p-1 + (p-1)(M-1) - (B)の右辺の最大値は
。M-1 - (C)の計算後は
。t \le 2p-1 + (p-1)(M-1) + (M-1)p=(2p-1)M - (D)の計算後は
。t \le (2p-1)M / M = 2p-1
よってループを何度繰り返しても
したがって
以上で定理の証明が終わりました。
Pythonによるサンプルコード
mont.pyにmont(x, y)のサンプルコードを置きました。
いくつかの素数
p'の求め方
最後に素数
下位64ビットしか見ないので素数
今求めたい X<<i
を加算する、ということをくりかえせばOKです。
p'が求まれば、M' = (1 + p' p)/MによりM'も求まります。
def getMontgomeryCoeff(p):
X = p & (M-1)
ret = 0
t = 0
for i in range(L):
if (t & (2**i)) == 0:
t += X << i
ret += 1 << i
return ret
まとめ
PythonによるMontgomery乗算のコードと数学的な性質の紹介をしました。次回はこの関数を用いて実際に計算する方法とC++による実装を紹介します。
Discussion