ショアのアルゴリズムの証明
アルゴリズム 1
単位元がであるグループの元が、オーダーとする。それならば、離散対数問題は次のアルゴリズムに従って、多くてもステップ以内に解ける。
ステップ 1.
ステップ 2.
二つのリストとを作る。
ステップ 3.
を見つける。
ステップ 4.
はの解である。
説明
基本的にグループの元がオーダーである場合、離散対数問題は多くてもステップ以内に解ける。がオーダーであるとは、少なくともが成り立つことを意味する。したがって、の中にはを満たすが存在することが簡単に確認できる。
シャンクスのアルゴリズムは、この計算量をまで落としてくれる。暗号に適用される離散対数問題であれば、はかなり大きな数であろうから、半分以上計算を減らすことができるので、大きな意味がある。
ベビーステップとジャイアントステップは、を掛けて作られるリストと、を掛けて作られるリストから出た言葉だ。
証明
パート 1. 存在性
であることを示さなければならない。
をで割った商を、余りをとすると、のように表せる。
するとなので そして である。なのでであり、なのでである。
パート 2. 時間複雑性
を見つけるためにはリストをソートする必要があり、最適な比較ソートアルゴリズムを使用すると回の計算が必要である。
であるため、
■
コード
以下は、R言語で実装されたシャンクスのアルゴリズムである。素因数分解コードとオーダーを求めるコードが使用された。
prime = read.table("../attachment
/cfile8.uf@25411C3C5968BBE322F0D4.txt"); prime = prime[,1]
factorize<-function(p)
{
q=p
factors<-numeric(0)
i=1; j=1
while(q!=1)
{
if(q%%prime[i]) {i=i+1}
else
{
q<-q/prime[i]
factors[j]<-prime[i]
i=1
j=j+1
}
}
return(factors)
}
order<-function(g,p,h=1) #Calculate a order of g in modulo p
{
qe<-table(factorize(p-1))
qe<-rbind(as.numeric(names(qe)),qe)
divisor<-qe[1,1]^(0:qe[2,1])
if((length(qe)/2)==1) {return(qe[1,1]^qe[2,1])}
for(i in 2:(length(qe)/2)) {divisor=c(divisor%*%t(qe[1,i]^(0:qe[2,i])))}
for(i in divisor) {if((FPM(g,i,p))%%p==1) break;}
return(i)
}
shanks<-function(g,h,p)
{
N<-order(g,p)
n<-1+floor(sqrt(N))
gn<-FPM(g,-n,p) #gn := g^{-n}
x<-p
List\_1<-numeric(n+1)
List\_1[1]=1
for(i in 1:n) {List\_1[i+1]=(List\_1[i]*g)%%p}
List\_2<-numeric(n+1)
List\_2[1]=h
for(i in 1:n) {List\_2[i+1]=(List\_2[i]*gn)%%p}
for(i in 0:n+1) {
for(j in 0:n+1) {
if (List\_1[i]==List\_2[j]) {x[length(x)+1]<-((i-1)+(j-1)*n)}
}
}
return(min(x))
}
shanks(11,21,71)
FPM(11,37,71)
shanks(156,116,593)
FPM(156,59,593)
shanks(650,2213,3571)
FPM(650,319,3571)
上記コードを実行した結果は以下の通りであり、連続べき乗法で検算して、正しく動作していることを確認した。
も参照
離散対数問題の難しさを利用したセキュリティアルゴリズム
離散対数問題に対する攻撃アルゴリズム
Hoffstein. (2008). 「数学的暗号化への導入」: p80。 ↩︎