SSブログ

No.310 - 高校数学で理解するRSA暗号の数理(1) [科学]

\(\newcommand{\bs}[1]{\boldsymbol{#1}} \newcommand{\mr}[1]{\mathrm{#1}} \newcommand{\br}[1]{\textbf{#1}} \newcommand{\ol}[1]{\overline{#1}} \newcommand{\sb}{\subset} \newcommand{\sp}{\supset} \newcommand{\al}{\alpha} \newcommand{\sg}{\sigma}\newcommand{\cd}{\cdots}\)
No.235「三角関数を学ぶ理由」では、私たちが学校で勉強を学ぶ目的の一つが「論理的に考える力を養う」こととし、その典型例として数学をとりあげました。数学は「論理のみで成り立っている」からです。そのことを改めて示すために \(\mr{sin}\:\theta\) の微分が \(\mr{cos}\:\theta\) になることを、三角関数のそもそもの定義に立ち返って証明しました。

今回はその継続・発展で、別の数学の問題を取り上げます。現代社会で広く使われている公開鍵暗号(その中の RSA暗号)です。これを取り上げる理由 は、

◆  2000年にわたる数学(数論 = 整数論)の基礎の上に作られた暗号である。
◆  インターネットの重要技術の一つであり、現代社会のインフラとなっている。
◆  高校生程度の前提知識があれば、論理的思考を積み重ねることで十分に理解できる(= タイトルの「高校数学で理解する」の意味)。

の3点です。以下の文章は元々別の目的のために作ったものですが、ここに掲載することにします。


公開鍵暗号


公開鍵暗号とは、

◆  暗号化の手順と、そこで使用する暗号化のための "鍵" が公開されている(その鍵が "公開鍵")。
◆  暗号文を解読するための手順も公開されているが、それに使う "鍵" は秘匿されている(その鍵が "秘密鍵")。

というタイプの暗号です。公開鍵暗号のメリットは多々ありますが、一番のメリットは「鍵を配送するコストがかからない」ことです。全ての鍵を秘匿する暗号だと、その鍵をどうやって配送して暗号化をしたい人に届けるかが大きな問題となります。暗号化通信で配送するというのは解決になりません。その暗号化通信の暗号鍵をどうやって配送するかという問題が残るからです。

公開鍵暗号では暗号化のための鍵がオープンなので、配送のコストはゼロです。暗号文を受け取りたい人が公開鍵と秘密鍵を生成し、公開鍵をオープンにすると誰でもその人に暗号文を送ることができます。

公開鍵暗号の設計の最大のポイントは、あたりまえですが、公開鍵から秘密鍵を推定したり導出したりできないことです。まさにそこに数学が使われていて、暗号文を解読できないようになっています。この「暗号化の鍵を公開してしまう」という革新的なアイデアというか、まさに "究極の逆転の発想" を論文として発表したのは、当時スタンフォード大学の研究者だったディフィー(米)とヘルマン(米)で、1976年のことでした。

Turing Award 2015.jpg
ディフィーとヘルマンは公開鍵暗号の発明の功績で、コンピュータ・サイエンス分野のノーベル賞といわれるチューリング賞を 2015年に受賞した。

そのディフィーとヘルマンのアイデアに基づいた最初の暗号が RSA暗号で、現代でも盛んに使われています。これは 1978年に MIT のリベスト(米)、シャミア(イスラエル)、エーデルマン(米)の3人のよって発明され、3人の頭文字をとって RSA と呼ばれています。

実はこの RSA暗号は、実用として何に使ったらいいのか、発表当時は使い道が分からなかったといいます。それが現代ではインターネットによる通信の重要技術として広く使われている。これにはコンピュータの処理速度の飛躍的向上も貢献しています。革新的な技術は、その応用環境が整った時点で、後から実用化される。よくあることです。

Turing Award 2002.jpg
RSA暗号を発明した3人は、チューリング賞を 2002年に受賞している。

以下、このRSA暗号の数理を順に見ていきます。


RSA暗号の例題


まずRSA暗号はどういうものか、それを極めて簡単な例題で説明します。

平文ひらぶん(=暗号化する文)を \(P\) で、またそれを暗号化した暗号文を \(C\) で表します。例題として平文は1文字だけの英字で、それを整数に変換したものとします。RSA暗号にちなんで大文字の R の1文字だけを平文の例とします。コンピュータで使われる ASCII(アスキー)コードでは、英大文字・英小文字・数字・特殊記号を \(1\)~\(128\) の数で表すので、それを使って数字化すると R は 82 です。つまり、

\(P=82\)

が例題の平文です。公開鍵は2つの数字のペア \((e,n)\)、秘密鍵は一つの数字 \(d\) で、例題としては、

公開鍵 : \(e=133,\:n=143\)
秘密鍵 : \(d=37\)

とします。この公開鍵と秘密鍵の作り方は後で述べます。平文から暗号文への変換(=暗号化)と、暗号文から平文への変換(=復号化)を次の計算で行います。以降の記述では、\(\bs{a}\)\(\bs{b}\) で割った余り(=剰余)を "\(\bs{a\:\mr{mod}\:b}\)" と書きます(プログラム言語や EXCEL で \(\mr{mod}(a,\:b)\) と書くのと同じ意味です)。

暗号化 : \(C=P^e\) \(\mathbf{mod}\) \(n\)
復号化 : \(P=C^d\) \(\mathbf{mod}\) \(n\)

例題の平文、\(P=82\) をこの暗号化の式に入れると、

\(C=82^{133}\) \(\mathbf{mod}\) \(143=4\)

となり、平文 "\(82\)" に対する暗号文は "\(4\)" です。\(82^{133}\) は巨大な数ですが、剰余を求めるときにこの巨大数を計算する必要は全くありません。上の程度の計算なら電卓でも簡単にできます。そのやり方は後ほど示します(「4. RSA暗号の証明」)。暗号文の復号化は、暗号文 "\(4\)" を復号化の式に入れると、

\(P=4^{37}\) \(\mathbf{mod}\) \(143=82\)

となり、元の平文である "\(82\)" が復元できました。なお、この例では平文をわずか1文字(\(2^7\) 以下の数字)としましたが、実際に使われる暗号では \(2^{1024}\) 程度(10進で約300桁程度)の数字です(= 平文を数字化したもの。平文が長い場合は複数に分割する)。また、公開鍵 \((e,\:n)\) と秘密鍵 \(d\) も同程度の大きさの数字です。

この計算で暗号化と復号化が可能なのは、公開鍵と秘密鍵の作り方に工夫があるからです。まず \(n=143\) は2つの素数 \(p=11\) と \(q=13\) の積です。

また \(e\) は、\(e\) と \((p-1)(q-1)=120=2^3\cdot3\cdot5\) との最大公約数が \(1\) であるように決めてあります。\(e=133=7\cdot19\) なので、\(133\) と \(120\) との共通の約数は \(1\) だけです。さらに秘密鍵である \(d\) は、

\(d\cdot e\) \(\mathbf{mod}\) \((p-1)(q-1)=1\)

となるように決めてあります。\(37\cdot133=4921=41\cdot120+1\) なので成り立っています。後で説明しますが、\(e\) と \((p-1)(q-1)\) との最大公約数が \(1\) なので、このような \(d\) が必ず存在します。このように鍵を仕込んでおくと暗号化と復号化が可能になる。そのことを証明するのが、本記事の目的です。その証明を、前提とする数学知識を最小限にしてやってみたいと思います。


公開鍵暗号は「公開鍵から秘密鍵が導出できない」ことが必須です。RSA暗号では、\(n=p\cdot q\) と素因数分解ができれば、

\(d\cdot e\) \(\mathbf{mod}\) \((p-1)(q-1)=1\)

の式を解いて \(d\) が求まります。しかし実用で使われるRSA暗号は最低でも \(n\) の桁数が10進数で300桁程度です(2進数で 1024ビット程度。平文も同等の長さ)。この程度の大きさの整数の素因数分解は超高速コンピュータをもってしても困難です。もしコンピュータの速度がさらに向上するなら、鍵の桁数をさらに大きくすればよい。この素因数分解の困難性が、RSA暗号が成り立つ理由です。


以降でRSA暗号の暗号化と復号化の式が成り立つことの証明を行います。さらに、単に成り立つことだけでなく、RSA暗号に関わる各種の式が計算可能であることの説明をします。"式が正しい" ことと、その "式が実用的に計算可能である" ことは違うからです。素因数分解がまさにその例です。

まず、整数の性質についての用語の定義からです。用語は RSA暗号の式の証明に必要なものだけに絞ります。以降に現れる "数" やそれを表す記号は、ほとんど場合は整数のことですが、自然数( \(1\) 以上の整数)を意味する場合もあります。どちらかは文脈から明らかなので、いちいち断りなく使います。


準備:用語の定義


割り切る・約数・因数・最大公約数
整数 \(N\) を \(a\) で割ったときの余りがゼロのとき、\(\bs{N}\)\(\bs{a}\) で割り切れると言い、また、\(\bs{a}\)\(\bs{N}\) を割り切ると言います。このことを記号を使って、

\(a|N\)

と書きます。またこのときの \(a\) を \(N\) の約数と呼びます。\(N|N\) と \(1|N\) は常に成り立つので、\(1\) と \(N\) は \(N\) の約数です。

\(N\) が 2つ以上の数の積で表されるとき、そのおのおのの数を \(N\) の因数と呼びます。因数は約数と同じものですが、見方の違いと言えるでしょう。

2つの数、\(N\) と \(M\) があったとき、共通の約数を公約数と言います。また、公約数のうち最大のものを最大公約数と呼び、\(\mr{gcd}(N,M)\) で表します。

素数と素因数分解
\(2\) 以上の整数 \(N\) の約数が \(1\) と \(N\) のみのとき、\(N\) を素数と言い、そうでない数を合成数と言います。合成数は \(1\) と \(N\) 以外の約数を持ちます。約数(=因数)が素数のとき、それを素因数と呼びます。\(N\) が素数の場合は \(N\) が素因数です。

合成数は素因数の積で表現できます(=素因数分解)。なぜなら、定義によって合成数 \(N\) は、\(1\) でも \(N\) でもない数 \(a\) と \(b\) を使って \(N=a\cdot b\) と表現(=分解)できますが、\(a\) や \(b\) が合成数なら、さらに分解を繰り返すことによって最終的には素数の積にたどり着くからです。なお便宜上、素数はそれ自身が素因数分解であるとします。

「素数」と「大きな数の素因数分解の困難性」が RSA暗号の基礎になっているのは、例題で説明した通りです。

素因数分解の一意性
素因数分解は、かけ算の順序を無視して一意に決まります(=素因数分解の一意性)。これは自明のように思えますが、証明をすると次の通りです。

いま(かけ算の順序は無視して)異なった2種類の素数列の積で表現できる合成数がある(=素因数分解が一意ではない)と仮定します。すると、そのような最小の数、\(N\) があるはずです。このとき \(N\) は、\(p_i\) と \(q_i\) を素数として、

\(N=p_1\:p_2\:p_3\:\cd\:p_r=q_1\:q_2\:q_3\:\cd\:q_s\)

と表現できます。ここで \(p_1\) に着目すると \(p_1|N\) なので、\(p_1|q_i\) となる \(q_i\) があるはずです。かけ算の順序は無視するので、\(p_1|q_1\) として一般性を失いません。ところが \(q_1\) は素数なので、\(q_1=p_1\) しかあり得ない。そこで式の全体を \(p_1\) で割ると、

\(\dfrac{N}{p_1}=p_2\:p_3\:\cd\:p_r=q_2\:q_3\:\cd\:q_s\)

となります。これは \(\dfrac{N}{p_1}\) が2つの異なった形に素因数分解できることを示しています。ところが \(\dfrac{N}{p_1}\) は \(N\) より小さい数なので「\(N\) が2つの異なった形に素因数分解できる最小の数」ということに矛盾します。従って「2つの異なった形で素因数分解できる数がある」という仮定が誤りであり、素因数分解の一意性が示されました。

互いに素
整数 \(N\) と 整数 \(M\) の最大公約数が \(1\) のとき、つまり \(\mr{gcd}(N,M)=1\) のとき、「\(N\) と \(M\) は互いに素である」と言います。これは \(N\) と \(M\) が共通の素因数を持たないことと同じです。なお、\(\mr{gcd}(N,1)=1\) は常に成り立つので、\(1\) は他の数と互いに素です。

以降の、RSA暗号の証明に至るプロセスでは「互いに素」に関連した数々の定理や証明が出てきます。RSA暗号は「素数」と「互いに素」の上に構築された暗号です。


用語の定義はここまでです。以降はRSA暗号の成立性の証明に入ります。まず、数の "合同" の概念からです。


1. 合同


合同の概念はRSA暗号の根幹の一つです。\(m\) を \(2\) 以上の整数とするとき、2つの整数 \(a,\:b\) について

・ \(a\) を \(m\) で割ったときの余りと、\(b\) を \(m\) で割ったときの余りが等しいとき、あるいは同じことですが、
・ \((a-b)\) が \(m\) で割り切れるとき、つまり \(m|(a-b)\) のとき、

\(\bs{a}\)\(\bs{b}\)\(\bs{m}\) を法として合同であると言い、

\(a\equiv b\:(\mr{mod}\:m)\)

と書きます。少々ややこしいですが、はじめに書いたように "\(a\) \(\mathbf{mod}\) \(b\)" とすると「\(a\) を \(b\) で割った余り」の意味です。以下に、合同の性質でRSA暗号の証明に必要なものをあげます。

1.1

\(a\equiv b\:(\mr{mod}\:m)\) かつ、
\(c\equiv d\:(\mr{mod}\:m)\) のとき、

1.1a \(a+c\equiv b+d\:(\mr{mod}\:m)\)

1.1b \(a-c\equiv b-d\:(\mr{mod}\:m)\)

1.1c \(ac\equiv bd\:(\mr{mod}\:m)\)


これらの性質は、それぞれの数を、

\(\begin{eqnarray} &&a&=k_a\cdot m+r_1\\ &&b&=k_b\cdot m+r_1\\ &&c&=k_c\cdot m+r_2\\ &&d&=k_d\cdot m+r_2\\ \end{eqnarray}\)

というように書いて計算をすればすぐにわかります。たとえば 1.1c(合同式の乗算)を証明するには、\(a\) と \(c\) の式をかけ算し、\(b\) と \(d\) の式をかけ算して、

\(m|(ac-r_1r_2)\)
\(m|(bd-r_1r_2)\)

が得られますが、2つの数が共に \(m\) で割り切れると、その差も \(m\) で割り切れます。従って、

\(m|((ac-r_1r_2)-(bd-r_1r_2))\)
\(m|(ac-bd)\)
\(ac\equiv bd\:(\mr{mod}\:m)\)

となります。

1.2 合同式の累乗(冪乗)

\(a\equiv b\:(\mr{mod}\:m)\) なら、\(2\)以上の \(r\) について、

\(a^r\equiv b^r\:(\mr{mod}\:m)\) である。


これは 1.1c で、\(c=a\)、\(d=b\) とおいて 1.1c を "繰り返して使う" ことでわかります。"繰り返して使う" ことを証明として書くなら数学的帰納法になるでしょう。以降は「互いに素」に関連した合同の性質です。

1.3 互いに素(1)

\(ax\equiv bx\:(\mr{mod}\:m)\) かつ、
\(x\) と \(m\) が互いに素なら、

\(a\equiv b\:(\mr{mod}\:m)\)


合同の定義により

\(m|(ax-bx)\)
\(m|x(a-b)\)

となります。ここで一般的に次の 1.3a が成り立つことに注意します。

1.3a

\(m\) は \(x\) と互いに素とする。

\(m|xn\) ならば \(m|n\)


\(m\) と \(x\) は互いに素なので、\(m\) と \(x\) に共通の素因数はありません。従って、\(m\) を素因数分解したときに現れる素因数は、すべて \(n\) の素因数のはずです。でないと、\(m|xn\) とはならないからです。従って \(m|n\) となります。このことを \(m|x(a-b)\) に適用すると、

\(m|(a-b)\)
\(a\equiv b\:(\mr{mod}\:m)\)

となり、1.3 が証明されました。1.3 は以降の証明にたびたび出てくる重要な定理です。1.3 を一般化したのが次の 1.4 です。


1.4 互いに素(2)

\(ax\equiv by\:(\mr{mod}\:m)\) かつ、
\(\phantom{a}x\equiv\phantom{b}y\:(\mr{mod}\:m)\) かつ、
\(x\) と \(y\) は \(m\) と互いに素なら、

\(a\equiv b\:(\mr{mod}\:m)\)


\(a,\:b,\:x,\:y\) を、\(m\) と 剰余 \(r\) を使って次のように表します。

\(\begin{eqnarray} &&a&=k_a\cdot m+r_a\\ &&b&=k_b\cdot m+r_b\\ &&x&=k_x\cdot m+r\\ &&y&=k_y\cdot m+r\\ \end{eqnarray}\)
 \((0\leq\:r_a,\:r_b,\:r\: < m)\)

このようにおくと、\(ax\equiv by\:(\mr{mod}\:m)\) より、

\(r\cdot r_a\equiv r\cdot r_b\:(\mr{mod}\:m)\)

となります。一方、\(r\) と \(m\) は互いに素です。なぜなら、もし \(r\) と \(m\) が \(1\) ではない共通の約数 \(c\) をもつとすると、上の \(x\) の式から \(c\) は \(x\) の約数にもなり、\(x\) と \(m\) が互いに素ではなくなるからです。また、\(y\) の式から \(c\) は \(y\) の約数でもあり、\(y\) と \(m\) が互いに素という前提にも反します。このように \(r\) と \(m\) は互いに素なので 1.3 を使って、

\(r_a\equiv r_b\:(\mr{mod}\:m)\)

となりますが、\(0\leq\:r_a,\:r_b\: < m\) なので、\(r_a=r_b\) となり、

\(a\equiv b\:(\mr{mod}\:m)\)

が示されました。

1.5 互いに素(3)

\(m\) と \(n\) は互いに素とする。

\(a\equiv b\:(\mr{mod}\:m)\) かつ、
\(a\equiv b\:(\mr{mod}\:n)\) なら、

\(a\equiv b\:(\mr{mod}\:mn)\)


\(a\equiv b\:(\mr{mod}\:m)\) なので、合同の定義から \(m|(a-b)\) です。また、\(a\equiv b\:(\mr{mod}\:n)\) なので、合同の定義から \(n|(a-b)\) であり、\(a-b=k_1n\) と表せます。この式の \(a-b\) を \(m|(a-b)\) に代入すると、

\(m|k_1n\)

となります。\(m\) と \(n\) は互いに素なので 1.3a を使うと、

\(m|k_1\)

となり、従って \(k_1=k_2m\) と表せることになります。この \(k_1\) を \(a-b=k_1n\) に代入すると、

\(a-b=k_2mn\)
\(mn|(a-b)\)
\(a\equiv b\:(\mr{mod}\:mn)\)

となって 1.5 が証明できました。


合同には数々の性質や定理がありますが、RSA暗号の証明に必要なものは以上です。次に、2つの数の最大公約数を求める「ユークリッドの互除法」です。これは最大公約数を求める計算方法というだけでなく、RSA暗号において公開鍵と秘密鍵を生成する際に必須のものです。


2. ユークリッドの互除法


ユークリッドの互除法は 2つの自然数(\(a\) と \(b\)。\(a > b\) とします)の最大公約数を求める計算方法です。これはユークリッドの数学書である『原論』にあります。『原論』は紀元前 300年頃の成立といいますから、2300年ほど前の書物ということになります。

この計算方法では、割り算(除算)を何ステップか繰り返します。割り算において被除数(=割られる数)と除数(=割る数)、(=答)、剰余(=余り)の関係は、

被除数 = 商 \(\times\) 除数 + 剰余

ですが、まず第1ステップとして、

被除数1 = \(a\)
除数1= \(b\)

とおき、

被除数1 = 商1 \(\times\) 除数1 + 剰余1

の計算をして、商1と剰余1を求めます。次に第2ステップとして、

被除数2 = 除数1
除数2= 剰余1

とおいて割り算を行い、商2と剰余2を求めます。つまり、

被除数2 = 商2 \(\times\) 除数2 + 剰余2

です。この「除数と剰余を新たな被除数と除数にして割り算をする」ステップを次々と繰り返して行くと、剰余は次第に小さくなっていき、ついには剰余がゼロ(= 被除数が除数で割り切れる)となります。この時点での除数(= 一つ前のステップの剰余)が \(a\) と \(b\) の最大公約数です。

なぜそうなるのかが以下ですが、ポイントは割り算の式から明らかなように「被除数と除数の公約数は、剰余の約数でもある」ことです。つまり \(a\) と \(b\) の約数であるという性質が剰余に引き継がれ、それは割り算のステップを繰り返してもずっと続きます。しかも、剰余はステップが進むにつれて小さくなっていくので、最大公約数に近づく。そして割り切れたときの除数(一つ前のステップの剰余)は、約数であると同時に最大の約数である。おおまかにはそのような理解です。


2.1 ユークリッドの互除法

\(a\)と \(b\) を自然数とし、\(a > b\) とする。

\(\begin{eqnarray} &&a&=q_1\cdot b_1+r_1 &\cd\:(1)\\ &&b&=q_2\cdot r_1+r_2 &\cd\:(2)\\ &&r_1&=q_3\cdot r_2+r_3 &\cd\:(3)\\ &&r_2&=q_4\cdot r_3+r_4 &\cd\:(4)\\ &&&\vdots&\\ &&r_{i-4}&=q_{i-2}\cdot r_{i-3}+r_{i-2} &\cd\:(i-2)\\ &&r_{i-3}&=q_{i-1}\cdot r_{i-2}+r_{i-1} &\cd\:(i-1)\\ &&r_{i-2}&=q_{i\phantom{-0}}\cdot r_{i-1}+r_{i\phantom{-0}} &\cd\:(i)\\ &&r_{i-1}&=q_{i+1}\cdot r_i &\cd\:(i+1)\\ \end{eqnarray}\)

となったとき、

\(\mr{gcd}(a,b)=r_i\)

である。


\(a\) と \(b\)(\(a > b\))の公約数を \(x\) とします。すると、\(x|a\) かつ \(x|b\) なので、\((1)\) 式から \(x|r_1\) になります。この \(x|r_1\) と \(x|b\) から \((2)\) 式を使って \(x|r_2\) が得られます。

その次には \(x|r_1\) 、\(x|r_2\) 、\((3)\) 式から \(x|r_3\) になる。以上を最後まで繰り返すと、次のようになります。

\(\begin{eqnarray} &&x|a, &x|b, &(1)式&\rightarrow x|r_1\\ &&x|b, &x|r_1, &(2)式&\rightarrow x|r_2\\ &&x|r_1, &x|r_2, &(3)式&\rightarrow x|r_3\\ &&&\vdots&&\\ &&x|r_{i-4}, &x|r_{i-3}, &(i-2)式&\rightarrow x|r_{i-2}\\ &&x|r_{i-3}, &x|r_{i-2}, &(i-1)式&\rightarrow x|r_{i-1}\\ &&x|r_{i-2}, &x|r_{i-1}, &(i)式&\rightarrow x|r_i\\ \end{eqnarray}\)

以上のように、最終的には \(x|r_i\) となり、

\(a\) と \(b\) の公約数は \(r_i\) の約数である

ことが示せました。同時に、

\(a\) と \(b\) の公約数の最大値は \(r_i\) である

ことも分かります。


次に、ユークリッドの互除法の最終プロセスに現れる剰余は、全てのステップの剰余の約数になっていることを示します。このことを最終ステップから順に遡って検証すると、

\(\begin{eqnarray} &&&&(i+1)式&\rightarrow r_i|r_{i-1}\\ &&r_i|r_{i-1},&&(i)式&\rightarrow r_i|r_{i-2}\\ &&r_i|r_{i-2},&r_i|r_{i-1},&(i-1)式&\rightarrow r_i|r_{i-3}\\ &&r_i|r_{i-3},&r_i|r_{i-2},&(i-2)式&\rightarrow r_i|r_{i-4}\\ &&&\vdots&&\\ &&r_i|r_2,&r_i|r_3,&(3)式&\rightarrow r_i|r_1\\ &&r_i|r_1,&r_i|r_2,&(2)式&\rightarrow r_i|b\\ &&r_i|b,&r_i|r_1,&(1)式&\rightarrow r_i|a\\ \end{eqnarray}\)

となり、\(r_i|b\) かつ \(r_i|a\)、つまり、

\(r_i\) は \(a\) と \(b\) の公約数である

ことが示せました。


従って、

◆  \(r_i\) は \(a\) と \(b\) の公約数である
◆  \(a\) と \(b\) の公約数の最大値は \(r_i\) である

の2つから、\(\mr{gcd}(a,b)=r_i\) が証明できました。

計算量
RSA暗号にとってのユークリッドの互除法の意味ですが、次の2つが重要です。まず第1に「2つの数の最大公約数は、素因数分解なしに計算できる」ことです。これはすなわち「2つの数が互いに素であることが素因数分解なしに示せる」ことも意味します。

我々が普通、学校で習う最大公約数の求め方は、2つの数を素因数分解して共通の素因数を探すというものでした。共通のものがなければ最大公約数は \(1\)(=互いに素)です。しかし、数が巨大になると素因数分解が困難になります(それがRSA暗号が成り立つゆえんです)。ユークリッドの互除法を使うと「最大公約数」や「互いに素」が素因数分解なしに示せるのです。

第2は、ユークリッドの互除法が高速に計算できることです。ユークリッドの互除法では、一つのステップの剰余が次のステップの除数になります。次のステップの剰余は除数より小さいので、

\(0 < r_{i+1} < r_i\)

となりますが、\(r_{i+1}\) が \(0\) に近いと計算は急速に収束します。また \(r_{i+1}\) が \(r_i\) に近い場合でも、その次のステップの商が大きくなり、\(r_{i+2}\) が \(0\) に近くなるので、計算は収束することになります。従って、最も計算が長引くのは、\(r_{i+1}\) が \(r_i\) の半分程度で、それが連続する場合だと推測できます。

実は、ユークリッドの互除法のステップが最も長くなるケースが知られています。それは 割り算の商が常に \(1\) になるケースで、\(a\) と \(b\) が(たまたま)フィボナッチ数列の隣り合う2項だとそうなります。フィボナッチ数列とは、

\(F_0=0,\) \(F_1=1\)
\(F_{n+2}=F_{n+1}+F_n\)

で定義される数列で、実際に書いてみると、

\(0,\:1,\:1,\:2,\:3,\:5,\:8,\:13,\:21,\:34,\:55,\:89,\:\cd\)

です。いま、\(a=144\)、\(b=89\) としてユークリッドの互除法の計算をしてみると

\(144=1\cdot89+55\)
\(\phantom{1}89=1\cdot55+34\)
\(\phantom{1}55=1\cdot34+21\)
\(\phantom{1}34=1\cdot21+13\)
\(\phantom{1}21=1\cdot13+\phantom{1}8\)
\(\phantom{1}13=1\cdot\phantom{1}8+\phantom{1}5\)
\(\phantom{11}8=1\cdot\phantom{1}5+\phantom{1}3\)
\(\phantom{11}5=1\cdot\phantom{1}3+\phantom{1}2\)
\(\phantom{11}3=1\cdot\phantom{1}2+\phantom{1}1\)
\(\phantom{11}2=2\cdot\phantom{1}1\)

となって、10ステップかかります。剰余が減る割合が常に 0.6 倍程度で、なかなか減りません。商が常に 1 なのでこうなります。しかし、なかなか減らないが毎回 0.6 倍程度にはなり、マクロ的には急速に小さくなる。証明は省略しますが、\(a\) と \(b\) が\(10\)進で \(N\) 桁の数字でフィボナッチ数列の隣り合う2項だった場合でも、ユークリッドの互除法は \(5\times N\) ステップ以下で終了します。

これは a とb が300桁程度の数字のとき、それが偶然にもフィボナッチ級数の隣り合う2項であるという最悪の最悪の場合でも 1500回の割り算で終了することを意味します。この程度の計算はもちろんコンピュータで可能です。


本題に戻ります。最初の「RSA暗号の例題」のところで公開鍵の作り方を書きました。まず2つの素数、\(p\) と \(q\) を選び、\(n=p\cdot q\) とします。次に、\((p-1)(q-1)\) との最大公約数が \(1\) であるような数(=互いに素)を選び、それを \(e\) とします。その \((e,\:n)\) のペアを公開鍵とするのでした。

\(n\) と同程度の大きさの数、\(e\) をランダムに選んだとき、その \(e\) が \((p-1)(q-1)\) と互いに素であるかどうかは、ユークリッドの互除法で検証可能です。そしてこの検証は \(p\) と \(q\) が巨大な数であっても可能です。つまりユークリッドの互除法は公開鍵が現実に作成できるという数学的根拠になっています。

アルゴリズム
2.1 において、\(a\) と \(b\) の最大公約数は \(r_i\) でしたが、この \(r_i\) は \((1)\)式における \(b\) と \(r_1\) の最大公約数にもなります。なぜなら、\(b\) と \(r_1\) の最大公約数を求めるためには \((2)\)式から互除法の計算を始めればよく、その結果は \(r_i\) になるからです。これは次を意味します。

2.1a 互除法の原理

\(a\)と \(b\) を自然数とし、\(a > b\) とする。\(a\) を

\(a=q\cdot b+r\:\:(1\leq q,\:0 < r)\)

と書き表せるとき、

\(\mr{gcd}(a,b)=\mr{gcd}(b,r)\)

である。


つまり、ユークリッドの互除法は

\(a\) と \(b\) の最大公約数を求める問題」を「より小さな数である \(b\) と \(r\) の最大公約数を求める問題」に置き換える

ものといえます。この置き換えは次々と可能で、置き換えるたびに問題がより "小さく" なっていく。これがユークリッドの互除法の原理です。ここで改めて 2.1a の証明をすると、次の通りです。

【証明】

表記を見やすくするため、
  \(\mr{gcd}(a,b)=x\)
  \(\mr{gcd}(b,r)=y\)
と書く。

\(x|a,\:\:x|b\) であり、\(a=q\cdot b+r\) から \(x|r\) である。従って、\(x\) は \(b\) と \(r\) の公約数である。公約数は最大公約数より以下なので、
  \(x\leq y\)
が成り立つ。一方、\(y|b,\:\:y|r\) なので \(y|a\) である。つまり \(y\) は \(a\) と \(b\) の公約数である。公約数は最大公約数以下なので、
  \(y\leq x\)
である。\(x\leq y\) かつ \(y\leq x\) なので、
  \(x=y\) つまり
  \(\mr{gcd}(a,b)=\mr{gcd}(b,r)\)
である。

もちろん、\(b|a\) であれば \(\mr{gcd}(a,b)=b\) です。

ユークリッドの互除法は "世界最古のアルゴリズム" と言われています。そして、アルゴリズムを記述するのに最適な言語はプログラミング言語です。2.1a の原理に基づき、ユークリッドの互除法で最大公約数を計算するプログラムを掲げます。

2.1b アルゴリズム

ユークリッドの互除法で a と b の最大公約数を求める関数 EUCLID(Javascriptで記述)

function EUCLID( a, b ) {
 if( a % b == 0 ) // ①
  return b;
 else
  return EUCLID( b, a % b );
}


① の "%" は Javascript の剰余演算子で、"a % b" は "a を b で割った余り" という意味です(a \(\mathbf{mod}\) b と同じ)。なお、このプログラムは a<b でも動作します。

もちろん、Javascript でなくても、C++ でも Python でも記述できます。このようにプログラムで書くと簡潔になって、ユークリッドの互除法というアルゴリズムの本質がクリアにわかります。

拡張ユークリッドの互除法
ユークリッドの互除法の "副産物" として、次の定理が成り立ちます。

2.2

\(a\) と \(b\) を自然数とする。このとき適当な整数 \(u\)、\(v\) をとって、

\(\mr{gcd}(a,b)=u\cdot a+v\cdot b\)

と表せる。


この定理の証明ですが、ユークリッドの互除法の計算過程を振り返ると、

\(\begin{eqnarray} &&a&=q_1\cdot b_1+r_1 &\cd\:(1)\\ &&b&=q_2\cdot r_1+r_2 &\cd\:(2)\\ &&r_1&=q_3\cdot r_2+r_3 &\cd\:(3)\\ &&r_2&=q_4\cdot r_3+r_4 &\cd\:(4)\\ &&&\vdots&\\ &&r_{i-4}&=q_{i-2}\cdot r_{i-3}+r_{i-2} &\cd\:(i-2)\\ &&r_{i-3}&=q_{i-1}\cdot r_{i-2}+r_{i-1} &\cd\:(i-1)\\ &&r_{i-2}&=q_{i\phantom{-0}}\cdot r_{i-1}+r_{i\phantom{-0}} &\cd\:(i)\\ &&r_{i-1}&=q_{i+1}\cdot r_i &\cd\:(i+1)\\ \end{eqnarray}\)

でした。ここで \((1)\) を変形して、

\(r_1=u_1\cdot a+v_1\cdot b\)

とします。\(u_1=1,\:\:v_1=-q_1\) です。次に、今求めた \(r_1\) と \((2)\) を使うと、

\(r_2=u_2\cdot a+v_2\cdot b\)

の形に表せることになります。\(u_2=-q_2,\:\:v_2=1+q_1q_2\) です。さらに、求まった \(r_1\) と \(r_2\) と \((3)\) を使って、

\(r_3=u_3\cdot a+v_3\cdot b\)

と表せることが分かります。このステップを順に続けていって \((i)\) まで到達すると、

\(r_i=u\cdot a+v\cdot b\)
  \(u,\:v\) は \(q_j\:(1\leq j\leq i)\) の式

となることがわかります。\(r_i=\mr{gcd}(a,b)\) だったので、2.2 が証明できました。\(u\) と \(v\) のうち、一つは正の整数、もう一つはゼロか負の整数です。一つがゼロであるのは、\(a=b\) のときです。なお、2.2 を満たす \(u\)、\(v\) に、

\(u\cdot a+v\cdot b=0\)

を満たす \(u\)、\(v\) をそれぞれ足し込んでも 2.2 が成立することが明白です。つまり 2.2 を満たす \(u\)、\(v\) は1組というわけではありません。なお、2.2 は次のように言い換えることができます。

2.2a 不定方程式の整数解

\(a\) と \(b\) を自然数とする。このとき、不定方程式

\(ax+by=\mr{gcd}(a,b)\)

は整数解をもつ。


拡張ユークリッドの互除法のアルゴリズム
ユークリッドの互除法を拡張して、\(a\) と \(b\) が与えられたとき、\(\mr{gcd}(a,b)\) と、

\(au+bv=\mr{gcd}(a,b)\)

を満たす \(u\) と \(v\)(=無数にある解のうちの一つのペア)を同時に計算してしまうアルゴリズムを考えてみます。

考え方は 2.1b のユークリッドの互除法と同じで、解くべき問題を「等価でより小さな問題」に置き換えます。そのために \(a=qb+r\) とおくと、2.1a より、

\(\mr{gcd}(a,b)=\mr{gcd}(b,r)\)

なので、問題は次のように書き換えられます。

\((qb+r)u+bv=\mr{gcd}(b,r)\)

ここで、未知数の \(u\) と \(v\) を次のように変換します。

\(u=V\)
\(v=U-qV\)

これを代入して式を整理すると

\(bU+rV=\mr{gcd}(b,r)\)

となり、"小さな問題" に変換することができました。この考え方でアルゴリズムを記述すると次のとおりです。

2.2b 拡張ユークリッドの互除法

\(a\) と \(b\) から拡張ユークリッドの互除法で(\(u,\:v,\) 最大公約数)の3つを同時に求める関数 extdEUCLID(Javascriptで記述)

function extdEUCLID( a, b ) {
 var r = a % b; // ①
 if( r == 0 )
  return { u : 0, v : 1, gcd : b }; // ②
 else {
  var q = Math.floor( a / b ); // ③
  var s = extdEUCLID( b, r ); // ④
  return {
   u : s.v, // ⑤
   v : (s.u - q * s.v), //
   gcd : s.gcd //
  };
 }
}


以下は、このアルゴリズムの補足説明です。

①  var:変数の宣言。%:剰余演算子。
②  a が b で割り切れるなら解が求まる。自然な解を関数値として返す。関数値は3つの変数(u, v, gcd)をひとまとめにしたオブジェクト。
③  商を求め、小数点以下を切り捨て整数化する。Javascript には実数・整数の区別がないので整数化(組み込み関数の Math.floor)が必要。
④  小さな問題として計算する。
⑤  変数を元に戻して、関数値(u, v, gcd)を返す。

この拡張ユークリッドの互除法のアルゴリズムは、2.1b のユークリッドのアルゴリズムとほぼ同じです。ただし、\(u\) と \(v\) の計算のために変数を変換しているので、最大公約数を計算したあとに元の変数値を求める必要があります(=⑤)。そこが違います。

このことから、拡張ユークリッドの互除法の計算量は、ユークリッドの互除法のほぼ2倍だと推測できます。計算は少々複雑になりますが、たとえ \(\bs{a}\)\(\bs{b}\) が巨大な数であっても、コンピュータで高速に計算できる。このことは次の「整数の逆数」の項で述べるように、RSA暗号にとっての重要ポイントになります。

整数の逆数
2.2 から導かれる次の定理は、RSA暗号にとって重要です。

2.3 逆数の存在

\(\mr{gcd}(a,m)=1\) なら(= \(a\) と \(m\) が互いに素なら)、

\(a\cdot b\equiv1\:(\mr{mod}\:m)\)

となる \(b\) が存在する。この \(b\) は \(m\) と互いに素であり、\(1\leq b < m\) の範囲では一意に定まる(= \(m\) を法として唯一)。


2.2 において \(a\)と互いに素な数 \(m\) を選び、\(b=m\) とおくと、\(\mr{gcd}(a,m)=1\) なので、適当な \(u\) と \(v\) をとることにより、

\(u\cdot a+v\cdot m=1\)

とすることができます。すなわち、

\(a\cdot u\equiv1\:(\mr{mod}\:m)\)

となり、2.3 が示されました。このとき \(a\cdot u\) は \(m\) と互いに素であり、また \(a\) と \(m\) は互いに素なので、\(b\) も \(m\) と互いに素になります。また、\(b_1\) と \(b_2\) の2つの解があるとすると、

\(a\cdot b_1\equiv1\:(\mr{mod}\:m)\)
\(a\cdot b_2\equiv1\:(\mr{mod}\:m)\)
\(a(b_1-b_2)\equiv0\:(\mr{mod}\:m)\)
\(m|a(b_1-b_2)\)

となり、\(a\) と \(m\) は互いに素なので 1.3a より、

\(m|(b_1-b_2)\)
\(b_1\equiv b_2\:(\mr{mod}\:m)\)

となります。従って、\(1\leq b < m\) の範囲に \(b\) があり、かつ、この範囲で \(b\) は一意に定まります。\(m\) を法として \(b\) と合同な数も解であることは明白ですが、それらの解は \(m\) を法として唯一です。


2.3 の "逆数" を計算するアルゴリズムは、拡張ユークリッドの互除法2.2 のアルゴリズム(2.2b)と基本的に同じです。

2.3a 逆数の計算アルゴリズム

\(m\) を法とする \(a\) の逆数を求める関数 INVERSE(Javascriptで記述)

function INVERSE( a, m ) {
 var b = extdEUCLID( a, m ).u % m; // ①
 return ( b + m ) % m;
//
 function extdEUCLID( a, b ) {
  var r = a % b;
  if( r == 0 )
   return { u : 0, v : 1, gcd : b };
  else {
   var q = Math.floor( a / b );
   var s = extdEUCLID( b, r );
   return {
    u : s.v,
    v : (s.u - q * s.v),
    gcd : s.gcd
   };
  }
 } // extdEUCLID 終わり
//
} // INVERSE 終わり


①で、extdEUCLID のアルゴリズム(2.2b)を使って u を求め、それを m 未満の自然数に直して答えの b を求めています。( b + m )% m は b が負の場合の配慮です。このアルゴリズムは正確に言うと、a と m が与えられたとき、

\(a\cdot b\equiv\mr{gcd}(a,m)\:\:(\mr{mod}\:m)\)

となる \(b\) を求めるアルゴリズムです。\(a\) と \(m\) が互いに素でなくても成立します。


この "逆数の存在定理" は RSA暗号において秘密鍵の算出に使われています。冒頭の「RSA暗号の例題」に書いたように、RSA暗号の公開鍵と秘密鍵は、まず秘密の2つの素数 \(p\) と \(q\) を決め、

\(n=p\cdot q\)

とします。そして \(e\) を、

\(\mr{gcd}(e,\:(p-1)(q-1))=1\)

となるように決め、\(n\) と \(e\) を公開鍵とするのでした。そして秘密鍵 \(d\) を、

\(d\cdot e\equiv1\:(\mr{mod}\:(p-1)(q-1))\)

を満たす数とします。この秘密鍵 \(d\) の計算は、\(\mr{mod}\:(p-1)(q-1)\) の世界で \(e\) の逆数を求めていることに他なりません。逆数の存在が保証されるのは、\(e\) を \((p-1)(q-1)\) と互いに素という条件で決めたからです。さらに、この逆数の計算アルゴリズムは 2.2b の拡張ユークリッドの互除法と同じなので高速に計算できることが重要ポイントです。


普通、整数の "逆数"は(整数の範囲で)定義できません( \(1\) 以外は)。しかし、"\(\mr{mod}\:m\) の合同の世界" では、\(m\) と互いに素な数 \(a\) に対して逆数が定義できることになります。つまり整数の範囲で「割り算」が定義できる。

たとえば \(\mr{mod}\:10\) の世界では \(7\times3=1\) であり、\(7\) の逆数は \(3\) です。割り算は逆数のかけ算なので、たとえば \(8\div7=8\times3=4\)(\(\mr{mod}\:10\) の世界)といった演算が定義できます。"検算" をすると \(4\times7=8\)(\(\mr{mod}\:10\) の世界)なので合っています。

\(\mr{mod}\:10\) の場合は実用的な意味はありませんが、\(p\) を素数としたとき「\(\mr{mod}\:p\) の世界」は大変重要です。というのも \(p\) 未満の自然数はすべて \(p\) と互いに素だからです。つまり \(p\) 未満の全ての自然数に対して "逆数" が定義できます。

2.3b 逆数の存在:法が素数

\(p\) を素数とする。\(p\) 未満の自然数 \(a\) に対して、

\(a\cdot b\equiv1\:(\mr{mod}\:p)\)

を満たす逆数 \(b\) が \(1\leq b < p\) の範囲で一意に定まる。また、異なる \(a\) に対する逆数 \(b\) は異なる。


2.3b はほとんど 2.3 と同じです。「異なる \(a\) に対する逆数 \(b\) は異なる」というところですが、もし \(1\leq i < j < p\) である \(i\) と \(j\) に対して、

\(i\cdot b\equiv1\:(\mr{mod}\:p)\)
\(j\cdot b\equiv1\:(\mr{mod}\:p)\)

となったとすると、

\((j-i)\cdot b\equiv0\:(\mr{mod}\:p)\)

ですが、\((j-i)\) も \(b\) も \(p\) と素なので矛盾します。異なる \(a\) に対する逆数 \(b\) は異なります。

このように逆数が存在するということは、\(p\) 未満の2つの自然数の "除算" が定義できます。さらに、\(0\) と \(p\) 未満の自然数を合わせると加減乗除が行えることになります。

加減乗除が定義された集合を「体(Field)」と呼びます。有理数、実数、複素数は「体」ですが、「\(0\) と \(p\) 未満の自然数」も体になります。これを \(\bs{F}_p\) と表記します。この集合の要素の数は有限個なので「有限体」です。 \(\bs{F}_{13}\) の場合(\(\mr{mod}\:13\))で "逆数" の計算をしてみると、

\(\phantom{1}1\cdot\phantom{1}1\equiv1\:(\mr{mod}\:13)\)
\(\phantom{1}2\cdot\phantom{1}7\equiv1\:(\mr{mod}\:13)\)
\(\phantom{1}3\cdot\phantom{1}9\equiv1\:(\mr{mod}\:13)\)
\(\phantom{1}4\cdot10\equiv1\:(\mr{mod}\:13)\)
\(\phantom{1}5\cdot\phantom{1}8\equiv1\:(\mr{mod}\:13)\)
\(\phantom{1}6\cdot11\equiv1\:(\mr{mod}\:13)\)
\(\phantom{1}7\cdot\phantom{1}2\equiv1\:(\mr{mod}\:13)\)
\(\phantom{1}8\cdot\phantom{1}5\equiv1\:(\mr{mod}\:13)\)
\(\phantom{1}9\cdot\phantom{1}3\equiv1\:(\mr{mod}\:13)\)
\(10\cdot\phantom{1}4\equiv1\:(\mr{mod}\:13)\)
\(11\cdot\phantom{1}6\equiv1\:(\mr{mod}\:13)\)
\(12\cdot12\equiv1\:(\mr{mod}\:13)\)

となり、\(0\) 以外の \(\bs{F}_{13}\) の要素は、その逆数(=逆元)と1対1に対応していることがわかります。

\(\bs{F}_p\) においては "整数" の加減乗除を "自由かつ厳密に" 行うことができます。これは、全ての情報を2進数に帰着させて扱うデジタル・コンピュータとの相性がよい。このため、公開鍵暗号の中には \(\bs{F}_p\) の演算を利用したものがあります。

なお、\(p\) を素数としたとき「\(p\) 未満の自然数はすべて \(p\) と互いに素」ということは「\((p-1)\:!\) と \(p\) は互いに素」ということです(" \(!\) " は階乗記号)。これは次の「フェルマの小定理」の証明に出てきます。


3. フェルマの小定理


フェルマの小定理は RSA暗号の根幹にかかわるものです。フェルマは17世紀フランスの大数学者(1607-1665)で、有名なフェルマの最終定理(大定理)と区別するために「小定理」の名があります。


3.1 フェルマの小定理

\(p\) を素数とし、\(a\) を \(p\) とは素な数とすると、

\(a^{p-1}\equiv1\:(\mr{mod}\:p)\)

が成り立つ。


これは少々意外な定理です。我々が高校までで習う素数は、自身と \(1\) 以外の約数を持たない数という定義か、素因数分解の定理か、そういうものです。「素数がもつ性質」に言及した定理はあまり思い浮かばない。しかしフェルマの小定理は、素数であれば必ずこうなると言っているわけです。これは次のように証明できます。

\(1,\:2,\:3,\:\cd\:,\:p-1\) のそれぞれに \(a\) をかけて、

\(a,\:2a,\:3a,\:\cd\:,\:(p-1)a\)

という数列を作ります。そして、それぞれの数を \(p\) で割った剰余を \(b_i\) とします。つまり、

\(\begin{eqnarray} &&a&\equiv b_1 &(\mr{mod}\:p)\\ &&2a&\equiv b_2 &(\mr{mod}\:p)\\ &&3a&\equiv b_3 &(\mr{mod}\:p)\\ &&&\vdots&\\ &&(p-1)a&\equiv b_{p-1} &(\mr{mod}\:p)\\ \end{eqnarray}\)

です。\(p\) は素数なので \(1\) から \((p-1)\) までの数は \(p\) と素であり、また \(a\) は仮定により \(p\) と素です。従って \(b_i\) が \(0\) になることはなく、\(1\leq b_i\leq\:(p-1)\) です。このとき、\(1\leq i,\:\:j\leq\:(p-1)\) である \(i,\:j\) について、

\(i\neq j\) であれば、必ず \(b_i\neq b_j\)

になります。なぜなら、もし \(b_i=b_j\) とすると、1.1b(合同式の減算)より、

\((i-j)a\equiv0\:(\mr{mod}\:p)\)

です。仮定より \(a\) は \(p\) と互いに素なので、1.3 により(\(1.3\) で \(b=0\) の場合)、

\((i-j)\equiv0\:(\mr{mod}\:p)\)

となりますが、\(1\leq i,\:\:j\leq\:(p-1)\) なので、

\(i=j\)

となり仮定に反します。つまり\(i\neq j\) であれば、必ず \(b_i\neq b_j\) です。ということは、\((p-1)\) 個の数、\(b_i(1\leq i\leq p-1)\) は全て違う数であり、つまり、\((1,\:2,\:3,\:\cd\:,\:p-1)\) を並び替えたものです。従って、\(b_i\) を全部かけ算すると、

\(b_1\:b_2\:b_3\:\cd\:b_{p-1}=(p-1)\:!\)

となります。そこで、1.1c(合同式の乗算)を上の \((p-1)\) 個の合同式に適用して左辺と右辺を全てかけ合わせてしまうと、

\((p-1)\:!\cdot a^{p-1}\)
  \(\equiv b_1\:b_2\:b_3\:\cd\:b_{p-1}\) \((\mr{mod}\:p)\)
  \(\equiv(p-1)\:!\) \((\mr{mod}\:p)\)

となります。ここで、\(p\) は素数なので \(p\) と \((p-1)!\) は互いに素です。すると 1.3 により、

\(a^{p-1}\equiv1\:(\mr{mod}\:p)\)

となり、証明が完成しました。



nice!(0)