「数学の言葉で世界を見たら」をPython で見たら… Vol.8 オイラーの定理と公開カギ暗号
第4話「素数はふしぎ」
書籍の著者 大栗博司 先生
書籍「数学の言葉で世界を見たら」第4話「素数はふしぎ」の Python写経活動記録 です。
公開カギ暗号の暗号化・復号化 を Python で擬似的に実行します。
では書籍を開いて数学の旅に出発です🚀

はじめに
このブログシリーズは、書籍「数学の言葉で世界を見たら」(幻冬舎)で学んだ「数学の楽しさ」を「Python 写経の形式」でご紹介いたします。
【引用表記】
この記事は、出典に記載の書籍に掲載された文章とデータを引用し、適宜、掲載文章・データを改変して書いています。
【出典】
「数学の言葉で世界を見たら」 第3刷、著者 大栗博司、幻冬舎

7 「公開カギ暗号」のカギ、オイラーの定理
学びポイント
公開カギ暗号の準備体操として、オイラーの定理を体感します。
素数を徐々に身体に沁み込ませていきましょう!
※この記事はライブラリのインポートが不要です。

オイラーの定理
先生のオイラーの定理前後の数式を一式引用いたします。
📊 オイラー定理の概要
オイラーの定理は $${n}$$ を一般の自然数 $${m}$$ で割った「余り」を考え、以下を条件としています。
$${m}$$ は素数でなくてもよい
$${n}$$ と $${m}$$ は $${1}$$ 以外に共通の因子を持たない
⇒ $${n, m}$$ の最大公約数は $${1}$$、互いに素と呼ぶ
📊 オイラー関数
$${m}$$ と互いに素な $${m}$$ 未満の自然数 $${n}$$ の個数を$${\varphi(m)}$$ とし、$${p}$$ と $${q}$$ が異なる素数のとき
$$
\begin{align*}
\varphi(p) &= p-1 \\
\varphi(p \times q) &= (p-1) \times (q-1)
\end{align*}
$$
となります。
$${\varphi(m)}$$ をオイラーの関数と呼びます。
📊 オイラーの定理
オイラーの定理は、自然数 $${n}$$ が $${m}$$ と互いに素ならば
$$
n^{\varphi(m)} = 1 + (m の倍数)
$$
となる主張です。
📊 オイラーの定理を公開カギ暗号に応用
$${m}$$ が2つの素数 $${p}$$ と $${q}$$ の積、つまり $${m=p \times q}$$ のときを考えます。
このとき、$${\varphi(p \times q)=(p-1) \times (q-1)}$$ なので、自然数 $${n}$$ が素数 $${p, q}$$ で割り切れなければ、以下が成り立ちます。
$$
n^{(p-1) \times (q-1)} = 1 + (p \times q の倍数)
$$

最後の式を、書籍 p.128 の例題 $${p=3,\ q=5,\ n=7}$$ を用いて実験します。
「オイラーの定理を公開カギ暗号に応用」の式を関数化します。
### p.128 オイラーの定理を公開カギ暗号に応用
# オイラーの定理の関数定義
def eulers_theorem(n, p, q):
# オイラーの定理の左辺の計算
left_side = n**((p-1)*(q-1))
# 左辺をp×qで割って、商quotient と余りremainder を算出
quotient, remainder = divmod(left_side, p*q)
# オイラーの定理の右辺の計算
right_side = remainder + p * q * quotient
# 結果の表示
print(f'n = {n}, p = {p}, q = {q}')
print(f'左辺 = {n}^({p-1} x {q-1}) = {left_side}')
print(f'右辺 = {remainder} + ({p} x {q} x {quotient}) = {right_side}')【実行結果】なし
では実験です!
# 2つの素数 p, q の設定
p, q = 3, 5
# nの設定
n = 7
# オイラーの定理の計算
eulers_theorem(n, p, q)【実行結果】
数式 $${n^{(p-1) \times (q-1)} = 1 + (p \times q の倍数)}$$ の左辺・右辺が等しく $${5764801}$$ になりました。
右辺は 余り $${1}$$ になっています。

この $${n, p, q}$$ や左辺・右辺の数式がどのように公開カギ暗号に関連するのでしょう?
ワクワクします!

8 クレジットカード番号を贈る、受け取る
学びポイント
公開カギ暗号の計算手順をステップ・バイ・ステップで味わいます。
2つの素数を決めることから始まる一連の暗号解読をお楽しみください!

6つのステップで暗号化・復号化を体感
書籍 p.130 ~ の RSA 暗号の6つの手順を Python で順番に実行します。
「魔法の杖 $${r}$$」をGETして、暗号を無事に解読できるでしょうか!?
シーンは、アマゾン社と顧客のオンライン通販のやりとりです。
1️⃣ ステップ1:【アマゾン】
2つの素数 p, q を選ぶ
### p.130~134 RSA暗号の手順、魔法の杖rの算出
# ステップ1: 【アマゾン】2つの素数を選ぶ
p, q = 3, 5
print('=== アマゾン:暗号の準備 ===')
print(f'ステップ1: p={p}, q={q}')【実行結果】

2️⃣ ステップ2:【アマゾン】
(p-1)×(q-1) と互いに素な自然数 k を選ぶ
# ステップ2: 【アマゾン】(p-1)×(q-1)と互いに素な自然数kを選ぶ
k = 3
print(f'ステップ2: k={k}')【実行結果】

3️⃣ ステップ3:【アマゾンから顧客へ】
公開カギ m=p×q を計算して、顧客に m, k を知らせる
# ステップ3: 【アマゾンから顧客へ】公開カギ m=p×q を計算して、顧客にm, kを知らせる
m = p * q
print('=== アマゾンから顧客へ公開カギの送信 ===')
print(f'ステップ3: m={m}, k={k}')【実行結果】

4️⃣ ステップ4:【顧客】
n < m であり n と m が互いに素になるような自然数 n を計算する
# ステップ4: 【顧客】n < m であり nとmが互いに素になるような自然数nを計算する
n = 7
print('=== 顧客:カード番号の準備 ===')
print(f'ステップ4: n=?')【実行結果】
カード番号想定の $${n}$$ は顧客内限定情報であり、アマゾン社には知らされません。

5️⃣ ステップ5:【顧客からアマゾン】
m, k を使って n を暗号化(=α)し、アマゾンに知らせる
# ステップ5: 【顧客からアマゾン】m, kを使ってnを暗号化(=α)し、アマゾンに知らせる
# n^k = α + (mの倍数) ⇔ α = n^k ÷ m の余り
alpha = n**k % m
print('=== 顧客からアマゾンへ暗号の送信 ===')
print(f'ステップ5: α={alpha}')【実行結果】
オイラーの定理 $${n^k = \alpha + (mの倍数)}$$ を用いて、余り $${\alpha}$$ を求めています。

6️⃣ ステップ6:【アマゾン】
暗号 α を n に復号
# ステップ6: 【アマゾン】暗号αをnに復号
# ステップ6-1: 自然数s, rを求める
# r × k = 1 + s × (p-1) × (q-1) ⇔ r = (1 + s * (p - 1)) * (q - 1) ÷ k。但し余り0
# s を1から順に設定して、余りが0になるrを探索
s = 1
while True:
r, remainder = divmod(1 + s * (p - 1) * (q - 1), k)
if remainder == 0:
break
s += 1
# ステップ6-2: 自然数rを用いてnを推定
# α^r = n + (mの倍数) ⇔ n = α^r ÷ m の余り
estimated_n = alpha**r % m
print('=== アマゾン:カード番号の推定 ===')
print(f'ステップ6: s={s}, r={r}')
print(f'推定した番号 n={estimated_n}')
print(f'実際の番号 n={n}')【実行結果】
アマゾン社は素数 p, q を使って無事に、カード番号想定の暗号 $${n}$$ を取得できました。
while 文の中で「魔法の杖 $${r}$$」を探索しています。

最後のステップもオイラーの定理が活用されています。
数式の詳細はぜひ書籍をご覧ください!

テキストよりも大きな値でRSA暗号を試す
6つのステップを一括実行する関数を作成して、$${p=2063,\ p=6029}$$ の暗号化・復号化をシミュレーションします!
まずは関数定義から。
## RSAの暗号化・復号化ステップの関数定義
def public_key_cryptography(p, q, k, n):
# ステップ1: 【アマゾン】2つの素数を選ぶ
print('=== アマゾン:暗号の準備 ===')
print(f'ステップ1: p={p}, q={q}')
# ステップ2: 【アマゾン】(p-1)×(q-1)と互いに素な自然数kを選ぶ
print(f'ステップ2: k={k}')
# ステップ3: 【アマゾンから顧客へ】公開カギ m=p×q を計算して、顧客にm, kを通知
m = p * q
print('=== アマゾンから顧客へ公開カギの送信 ===')
print(f'ステップ3: m={m}, k={k}')
# ステップ4: 【顧客】n < m であり nとmが互いに素になるような自然数nを計算する
print('=== 顧客:カード番号の準備 ===')
print(f'ステップ4: n=?')
# ステップ5: 【顧客からアマゾン】m, kを使ってnを暗号化(=α)、アマゾンに知らせる
# n^k = α + (mの倍数) ⇔ α = n^k ÷ m の余り
alpha = n**k % m
print('=== 顧客からアマゾンへ暗号の送信 ===')
print(f'ステップ5: α={alpha}')
# ステップ6: 【アマゾン】暗号αをnに復号
# ステップ6-1: 自然数s, rを求める
# r × k = 1 + s × (p-1) × (q-1) ⇔ r = (1 + s * (p - 1)) * (q - 1) ÷ k 余り0
# s を1から順に設定して、余りが0になるrを探索
s = 1
while True:
r, remainder = divmod(1 + s * (p - 1) * (q - 1), k)
if remainder == 0:
break
s += 1
# ステップ6-2: 自然数rを用いてnを推定
# α^r = n + (mの倍数) ⇔ n = α^r ÷ m の余り
estimated_n = alpha**r % m
print('=== アマゾン:カード番号の推定 ===')
print(f'ステップ6: s={s}, r={r}')
print(f'推定した番号 n={estimated_n}')
print(f'実際の番号 n={n}')【実行結果】なし
暗号化・復号化の実行に移ります。
%%time
### テキストよりも大きなp,q,k,nの値でRSA暗号化・復号化を試す
# 素数表の参考サイト: https://mathlandscape.com/prime-table/
## アマゾン側の設定
# 2つの素数 p, qの選定
p, q = 2063, 6029
# (p-1) × (q-1)と互いに素な自然数kの選定(ここでは素数を設定)
k = 61
## 顧客側の設定:クレジットカード番号に関連する値を想定
# p × qより小さく、p × qと互いに素な自然数nを選定(ここでは素数を設定)
n = 223
## 暗号化、復号化のステップ
public_key_cryptography(p, q, k, n)
print('-'*40)【実行結果】
カード番号 $${n}$$ を無事に推定できました!
今回使用した $${p, q}$$ の桁数では、🖥️処理時間は数秒程度です。

よかったら、このコードの $${p, q, k, n}$$ に別の数値を設定して、シミュレーションを楽しんでみて下さい🍀
おわり
シリーズの記事
次の記事
前の記事
目次
ブログの紹介
note で7つのシリーズ記事を書いています。
ぜひ覗いていってくださいね!
1.のんびり統計
統計検定2級の問題集を手がかりにして、確率・統計をざっくり掘り下げるブログです。
雑談感覚で大丈夫です。ぜひ覗いていってくださいね。
統計検定2級公式問題集CBT対応版に対応しています。
Python、EXCELのサンプルコードの配布もあります。
2.実験!たのしいベイズモデリング1&2をPyMC Ver.5で
書籍「たのしいベイズモデリング」・「たのしいベイズモデリング2」の心理学研究に用いられたベイズモデルを PyMC Ver.5で描いて分析します。
この書籍をはじめ、多くのベイズモデルは R言語+Stanで書かれています。
PyMCの可能性を探り出し、手軽にベイズモデリングを実践できるように努めます。
身近なテーマ、イメージしやすいテーマですので、ぜひぜひPyMCで動かして、一緒に楽しみましょう!
3.実験!岩波データサイエンス1のベイズモデリングをPyMC Ver.5で
書籍「実験!岩波データサイエンスvol.1」の4人のベイジアンによるベイズモデルを PyMC Ver.5で描いて分析します。
この書籍はベイズプログラミングのイロハをざっくりと学ぶことができる良書です。
楽しくPyMCモデルを動かして、ベイズと仲良しになれた気がします。
みなさんもぜひぜひPyMCで動かして、一緒に遊んで学びましょう!
4.楽しい写経 ベイズ・Python等
ベイズ、Python、その他の「書籍の写経活動」の成果をブログにします。
主にPythonへの翻訳に取り組んでいます。
写経に取り組むお仲間さんのサンプルコードになれば幸いです🍀
5.RとStanではじめる心理学のための時系列分析入門 を PythonとPyMC Ver.5 で
書籍「RとStanではじめる心理学のための時系列分析入門」の時系列分析をPythonとPyMC Ver.5 で実践します。
この書籍には時系列分析のテーマが盛りだくさん!
時系列分析の懐の深さを実感いたしました。
大好きなPythonで楽しく時系列分析を学びます。
6.データサイエンスっぽいことを綴る
統計、データ分析、AI、機械学習、Pythonのコラムを不定期に綴っています。
統計・データサイエンス書籍にまつわる記事が多いです。
「統計」「Python」「数学とPython」「R」のシリーズが生まれています。
7.Python機械学習プログラミング実践記
書籍「Python機械学習プログラミング PyTorch & scikit-learn編」を学んだときのさまざまな思いを記事にしました。
この書籍は、scikit-learnとPyTorchの教科書です。
よかったらぜひ、お試しくださいませ。
最後までお読みいただきまして、ありがとうございました。
いいなと思ったら応援しよう!
応援ありがとうございます。これからもがんばって記事を作成します!