Advanced Cryptography Program 2026 / Week 0 自習ノート
Week 0 は土台編です。扱うのは mod 演算・群環体・逆元・離散対数問題—— どれも「暗号の前に済ませておく数学」に見えて、実際には Week 1 以降でつまずく場所そのものです。
Week 1 の算術回路は F_p 上に組み、Week 2 の秘密分散も Beaver 三つ組も F_p 上で動き、 Week 3 は楕円曲線というもう一つの群の上に Schnorr を建てます。 前提はここに全部あります。単独で読めるように書いたので、 他の週で「これは何だったか」と思ったらここに戻ってきてください。
出発点
有限体の定義から始めると、いちばん大事なことが抜け落ちます。 先に「整数のままだと何が壊れるのか」を見ます。
秘密の値 x を、素朴に整数のまま計算に使うとします。3 つのことが同時に困ります。
① 大きさが秘密を漏らす。
x + 100 という値を見せられたら、それが 3 桁なら x も 3 桁だと分かります。
暗号で欲しいのは「見ても何も分からない値」なのに、
整数には大小という手がかりが最初から付いています。
② 割り算で分数が出る。
7 ÷ 2 は整数の世界から出てしまいます。かといって有理数まで広げると、
今度は分母がどこまでも育ちます。「その値」に固定できないのは、
あとで見る「回路の値」としては致命的です。
③ どこまでも大きくなる。 掛け算を繰り返せば桁は際限なく増えます。暗号は 256 ビットなら 256 ビットという固定長で扱いたいのに、整数は収まりません。
つまり欲しいのは、四則が全部できて、有限で、大小の手がかりがない世界。 この 3 つを同時に満たすものが有限体です。以降の全部はこの一言の展開です。
この 3 つが、そのまま設計になっている
| 整数だと困ること | 有限体での答え |
|---|---|
| 大小が秘密を漏らす | 順序が存在しない(⑤) |
| 割り算で外へ出る | 逆元の掛け算で中に閉じる(④) |
| 桁が育つ | p で巻いて固定長(②) |
右の列がこのノートの目次とほぼ一致します。 有限体の性質は「便利な数学」ではなく、暗号の要求から逆算された形だと思って読んでください。
先に言っておくこと
土台編で覚えるのは、最後に 3 つだけです。
「順序がない」「割り算は逆元の掛け算」「一方向だけ難しい」。 この 3 つが、Week 1 の回路制約・Week 2 のシェアの安全性・Week 3 の署名の安全性に、 それぞれ 1 対 1 で対応します。
この頁の地図
道具
「桁が育つ」を殺す道具が mod です。時計の比喩から入って、 最後は「正規化を忘れて課題に落ちる」という実務の話まで一気に降ります。
10 時の 5 時間後は 15 時ですが、時計の文字盤では 3 時です。 12 を超えたら 12 を引く——これが mod 12 の世界です。 数直線ではなく円周の上で計算していることになります。
なぜこれが暗号に効くのか: 何回足しても何回掛けても、 結果は必ず 0..11 の 12 個のどれかです。値が絶対に外へ出ない。 これが「固定長で扱える」の正体です。
a ≡ b (mod p) は「a − b が p の倍数」という意味です。
15 ≡ 3 (mod 12) は、15 と 3 が等しいのではなく、
12 で巻いた世界では同じ場所に来るということ。
15 ≡ 3 ≡ −9 ≡ 27 (mod 12)
ここが分岐点です。 ≡ で結ばれた数は無限にあります。 その無限の仲間から代表を 1 つ選ぶのが次のステップで、 プログラムが落ちるのはたいていそこです。
15, 3, −9, 27 はどれも mod 12 では同じものですが、
体の元として書くときは 0..11 の代表 3 に統一します。
この統一を正規化と呼びます。
−3 mod 7 = 4 (−3 + 7 = 4。「余り」ではなく「巻いた先」で考える)
30 mod 7 = 2 17 mod 7 = 3 0 mod 7 = 0
なぜ 0..p−1 なのか: どれを選んでも数学的には同じですが、 比較・保存・テストのためには表現が 1 つに決まっていなければ困るから。 数学の都合ではなく、実装の都合で決めた約束です。
多くの言語の % は符号を引きずります。
Python の -3 % 7 は 4 になりますが、
C / Java / JavaScript / Rust の -3 % 7 は -3 です。
正しい正規化: ((n % p) + p) % p
このノートの JS もこの 1 行で書いています。 「mod を取ったつもり」で負の値が残ると、値としては正しいのに 他の関数と噛み合わなくなります。次の実測がまさにそれです。
実測 1 — Week 2 の秘密分散が落ちる
正規化を忘れたシェアは、値が合っていても不合格になります。
share(-3, [70, -2], 67) の正解は [3, 65, 63]。
mod を取らない実装はこう落ちます。
AssertionError: Lists differ: [70, -2, -71] != [3, 65, 63]
70 ≡ 3、−2 ≡ 65、−71 ≡ 63 (mod 67) なので、
数学的にはどちらも同じ秘密を表しています。それでも落ちる。
「同じ」であることと「同じ表現である」ことは別だからです。
実測 2 — Week 3 の逆元が落ちる
拡張ユークリッドの戻り値は、負のことがあります。
schnorr-from-scratch の field_inv は、
extended_gcd(a % p, p) が返した x をそのまま返すと落ちます。
テストのメッセージがそのまま答えを言っています。
AssertionError: 逆元は 0..p-1 に正規化して返してください
あとで見るように、5⁻¹ mod 13 を拡張ユークリッドで解くと
素直に出てくるのは −5 です。正しい逆元です。
ただし代表元としては 8 でなければならない。
つまり
Week 1・2・3 の課題で最初にぶつかる壁は、暗号ではなく ((n % p) + p) % p です。
3 週にわたって同じ形で落ちるので、ここだけは手が覚えるまでやっておく価値があります。 このあとのラボとクイズは、全部この正規化の上で動いています。
階層
群・環・体は、暗記する 3 つの定義ではありません。 「その世界で何ができるか」を強い順に並べた階層です。 できることが増えるほど、条件は厳しくなります。
集合 G と演算 ∗ が群であるとは、次の 4 つが成り立つことです。
① 閉じている: a ∗ b は必ず G の中
② 結合則: (a ∗ b) ∗ c = a ∗ (b ∗ c)
③ 単位元 e がある: a ∗ e = e ∗ a = a
④ 逆元がある: 各 a に a ∗ a⁻¹ = e となる a⁻¹ が存在
a ∗ b = b ∗ a(可換)は別条件で、
満たすものをアーベル群と呼びます。暗号で使う群はたいてい可換です。
群の正体は「行って、戻れる」です。 単位元があるから「何もしない」が書けて、逆元があるから「元に戻す」が書ける。 暗号は「戻せない」を作りたいのに、道具の側は戻せる必要がある—— この緊張が離散対数(⑧)で効いてきます。
| 集合 | 演算 | 単位元 | 逆元 |
|---|---|---|---|
| 整数 Z | 加法 + | 0 | −a |
| F_p(p 個の元) | 加法 + | 0 | p − a |
| F_p*(0 を除いた p−1 個) | 乗法 × | 1 | a⁻¹ |
| 楕円曲線の点 E | 点の加算 + | 無限遠点 O | x 軸反転 −P |
下の 2 行が今週の主役です。
F_p* の乗法群と、楕円曲線の点の群。
この 2 つはまったく違う見た目をしていて、群としては同じ形をしています。
だから ⑧ で見るように、離散対数問題も同じ言葉で書けます。
環は + と × の両方があり、分配則 a(b+c) = ab + ac が成り立つ世界です。
加法については群(0 があり、−a がある)ですが、
乗法の逆元は要求されません。
例: 整数 Z。2 × ? = 1 を満たす整数はありません。
例: Z/nZ(n で割った余り、n は素数でなくてよい)。
環でできることは「+ と × と、その組み合わせ」だけです。 Week 1 の回路が「加算ゲートと乗算ゲートしかない」のは、 この定義に演算が 2 つしか無いことの直接の帰結です。 比較も分岐も、環の定義のどこにも書いてありません。
体は環であって、さらに 0 以外のすべての元に乗法逆元があるもの。 これでようやく四則が揃います。
群 ⊂ 環 ⊂ 体 (できることが増えるほど、条件は厳しくなる)
有理数・実数は無限個の元を持つ体。有限体は元の個数が有限な体で、 要素数を位数と呼びます。
位数は必ず素数のべき pn です。
n = 1 なら F_p(このノートの主役)、
n ≥ 2 なら拡大体 F_{p^n}——
既約多項式の根を追加して作る世界で、Week 0 のスライドの後半に出てきます。
この講座の課題で使うのはほぼ F_p の方なので、ここでは名前だけ置いておきます。
階層の全体像
| 構造 | 使える演算 | 逆元 | 例 | このプログラムでの出番 |
|---|---|---|---|---|
| 群 (Group) | 1 つだけ | その演算について必ずある | Z の加法、F_p* の乗法、EC の点 | Week 3(EC と Schnorr) |
| 環 (Ring) | + と × | 加法のみ保証 | 整数 Z、Z/6Z | 「+ と × しかない」の根拠 |
| 体 (Field) | + − × ÷ | 0 以外すべてに乗法逆元 | 有理数 Q、実数 R | 四則が揃う条件 |
| 有限体 F_p | + − × ÷ | 0 以外すべて | p が素数のときの Z/pZ | Week 1〜6 のほぼ全部 |
Week 1 のノートで「なぜ + と × だけなのか」と書いた答えが、この表の 2 行目です。 環の定義に演算が 2 つしか無いので、回路にも 2 種類のゲートしか無い。
核心
Z/6Z を見ます。0..5 の 6 個の世界です。ここで 2 × 3 を計算すると:
2 × 3 = 6 ≡ 0 (mod 6)
どちらも 0 でないのに、掛けたら 0 になりました。 こういう元を零因子と呼びます。整数の世界では絶対に起きないことです。
零因子があると何が壊れるか。約分ができなくなります。
2x ≡ 2y (mod 6) から x ≡ y は言えない
(x = 1, y = 4 なら 2·1 = 2, 2·4 = 8 ≡ 2。x ≠ y なのに一致)
そして逆元も存在しません。もし 2⁻¹ があったなら、
2 × 3 = 0 の両辺に掛けて 3 = 0 になってしまう。矛盾です。
p が素数なら、零因子は消えます。
a·b ≡ 0 (mod p) は p | a·b のこと。
p は素数なので p | a か p | b のどちらかでなければならず、
つまり a ≡ 0 か b ≡ 0。これが素数の効き目のすべてです。
この一点のために素数を使う
零因子が消える ⟺ 0 以外すべてに逆元がある ⟺ 体になる
この 3 つは同じことの言い換えです。暗号が素数を選ぶ理由は、速いからでも安全そうだからでもなく、 体にならないと割り算ができないから。
すぐ下のラボで、法を 6 → 7 → 9 → 11 → 12 → 13 と切り替えてください。
合成数を選ぶと乗法表に赤いマス(積が 0)が現れ、素数を選ぶと消えます。
見えているのはこの証明そのものです。
Week 1 での現れ方
零因子が無いことは、回路の健全性の根拠になっています。
(x−2)(x−5)(x−6) = 0 という制約は「x は 2 か 5 か 6」を意味します。
これが成立するのは、積が 0 なら因子のどれかが 0 だから。
零因子のある Z/6Z の上で同じ回路を書いたら、
許可リストに無い値でも制約を満たせてしまいます。
中核
有限体に「割り算」という演算はありません。あるのは逆元の掛け算だけです。 求め方は 3 通りあり、計算量も使える条件も違います。
a の乗法逆元 a⁻¹ とは、次を満たす元のことです。
a · a⁻¹ ≡ 1 (mod p)
そして割り算はこう定義されます。定義であって、変形ではありません。
b ÷ a := b · a⁻¹
同じことが加法にもあります。a の加法逆元は p − a で、
引き算は b − a := b + (p − a)。
有限体には「引く」も「割る」も無く、あるのは「逆元を足す・掛ける」だけです。
0 に逆元はありません。
0 · x = 0 がすべての x で成り立つので、1 になりようがない。
これは「まだ見つかっていない」ではなく「存在しない」です。
⑦ への伏線: この「0 だけは割れない」が、
楕円曲線の 2 倍算で y = 0 のときに
接線が垂直になって無限遠点に飛ぶという現象に直結します。
分母 2y が 0 になる、ただそれだけのことです。
3 つの求め方と、その計算量
| 方法 | 計算量 | 使える条件 |
|---|---|---|
| 総当たり | O(p) | いつでも(実用外) |
| フェルマーの小定理 ap−2 | O(log p) 回の乗算 | p が素数のときだけ |
| 拡張ユークリッド | O(log p)・最速 | gcd(a, p) = 1 なら合成数でも可 |
p が 2²⁵⁶ 級なら総当たりは即座に論外です。
実装で選ぶのは下 2 つで、Week 1 の採点器 solver.py は
pow(a, P−2, P)(フェルマー)、
Week 3 の課題は extended_gcd(拡張ユークリッド)を使います。
フェルマーが素数を要求する理由
ap−1 ≡ 1 が成り立つのは、p が素数だからです。
両辺を a で割れば ap−2 ≡ a⁻¹。
合成数の法に同じ式を当てると、静かに間違った値を返します——
例外も出ません。ラボで法 9 を選んで確かめてください。
手で追う — F₁₃ で 5⁻¹ を求める
13 と 5 に対してユークリッドの互除法を回します。
13 = 2·5 + 3
5 = 1·3 + 2
3 = 1·2 + 1 ← 余りが 1 になったので gcd(13, 5) = 1
gcd が 1 であることが、逆元が存在する条件です。 もし gcd が 1 でなければ、その時点で「逆元なし」が確定します。
余りが 1 になった式から、順に代入して戻します。
1 = 3 − 1·2
= 3 − 1·(5 − 1·3) = 2·3 − 1·5
= 2·(13 − 2·5) − 1·5 = 2·13 − 5·5
最後の形が ax + by = gcd の形(ここでは 13·2 + 5·(−5) = 1)です。
この式を mod 13 で見ると 13 の項が消えます。
2·13 − 5·5 = 1
→ −5·5 ≡ 1 (mod 13)
→ 5⁻¹ ≡ −5 ≡ 8 (mod 13)
検算: 5 · 8 = 40 = 3·13 + 1 ≡ 1 (mod 13) ✓
ここが Week 3 の落とし穴でした。
素直に出てくるのは −5 で、これは正しい逆元です。
でも 0..p−1 の代表に直さないと採点器に落とされる。
②の正規化が、そのままここで効いています。
513−2 = 511 ≡ 8 (mod 13)
指数 11 は 2 進で 1011 なので、繰り返し二乗法で
7 回の乗算で終わります(総当たりなら 8 回試す)。
p が大きくなるほど差は開き、p ≈ 2²⁵⁶ では
総当たり 2²⁵⁶ 回に対して、フェルマーは約 500 回です。
どちらも同じ 8 に着地します。 当然です——逆元は一意だから。
a·x ≡ 1 と a·y ≡ 1 なら、
両辺に掛け合わせて x ≡ y が出ます。
「求め方が 3 つある」は「答えが 3 つある」ではありません。
ラボ A
法 p を選ぶと、その世界の乗法表が描かれます。
積が 0 になったマスは赤、積が 1 になったマス(逆元のペア)は緑。
合成数(6, 9, 12)を選ぶと赤が現れ、素数(7, 11, 13)を選ぶと消えます。
それが「なぜ素数か」の答えそのものです。
—
—
零因子(0 でない 2 つを掛けて 0 になる組)
乗法表 — 縦 a × 横 b
逆元を 3 通りで求める(同じ答えに着地するか)
拡張ユークリッドの中身
—
見てほしいこと 1
合成数の表には、赤いマスが必ず現れる。
p = 6 なら 2·3 と 3·4 が 0。
p = 9 なら 3·3、3·6、6·6。
p = 12 にいたっては赤だらけです。
赤が 1 つでもあれば、その世界では割り算が定義できません。
見てほしいこと 2
素数の表では、各行にちょうど 1 つだけ緑がある。
「各行に 1 つ」=すべての元にちょうど 1 つの逆元がある。
零因子が消えることと、逆元が全員に行き渡ることが、同じ表の裏表として見えます。
さらに、素数の行はどれも 0..p−1 の全部を 1 回ずつ含みます
(a 倍は全単射)——これも零因子が無いことの言い換えです。
性質
整数から持ち込めなかったものがあります。順序です。 これは実装の都合ではなく、原理的に存在しないという話です。
F_7 で「1 < 2」と言えるでしょうか。言えません。証明は 3 行です。
もし 1 < 2 で、順序が加法と両立する(a < b なら a+c < b+c)なら
1 < 2 < 3 < 4 < 5 < 6 < 7 = 0 < 1
→ 1 < 1。矛盾。
時計の上で「3 時は 10 時より小さい」と言えないのと同じです。 巻いてしまう世界に、始点も終点もありません。
注意すべきは、3 < 5 という比較を書くこと自体はできることです。
代表元は 0..p−1 の整数なので、機械的には比較できます。
できないのは「+ と × と噛み合う順序」を持つこと。
3 < 5 の両辺に 4 を足せば 0 < 2、
さらに 4 を足せば 4 < 6、もう一度で 1 < 3——
足すたびに大小がひっくり返るので、比較として使えません。
Week 1 では枷になる
回路に x < 8 と書けません。
算術回路の制約は「式 = 0」の形しか無く、その式は + と × でできています。
不等式はそこに存在しないので、
x をビットに分解して 1 本ずつ縛る(range proof)という
遠回りをすることになります。
proof-of-exploit が許可リストを
(x−2)(x−5)(x−6) = 0 という積の形で書くのは、
「集合に入っている」なら + と × だけで表せるからです。
Week 2 では武器になる
シェアの大きさから秘密が推測できません。
秘密 s を share = r と s − r に分けたとき、
片方が 65 だったとして、それは「大きい秘密」を意味しません。
r は一様乱数で、s − r も一様分布。
大小に情報が乗らないので、大小からは何も漏れません。
もし整数のまま分けていたら、share = 1000000 を見た人は
「秘密もそのくらいの桁だな」と推測できてしまいます。
同じ性質が、片方では枷、片方では武器
順序が無いことは、有限体の欠点でも利点でもなく、ただの性質です。
Week 1(ZK)は「表現したいのに書けない」側に立つので枷になり、 Week 2(MPC)は「漏らしたくないのに漏れない」側に立つので武器になります。 どちらを向いているかで呼び方が変わるだけ—— 暗号の道具はだいたいこの形をしていて、 「制約」と「保証」は同じ 1 つの事実の裏表であることが多いです。
構造
群の中で 1 つの元を選び、それを掛け続けると何が起きるか。 ここで出てくる言葉が、⑧ の離散対数と Week 3 のフーリエ変換の両方で使われます。
同じ言葉で 2 つのものを指すので、最初に分けておきます。
群の位数: 群に含まれる元の個数
元の位数: gn = 1 となる最小の正整数 n
混同しやすいのは、しばしば一致するからです。
F_7* の群の位数は 6、そして元 3 の位数も 6。
一致する元のことを生成元と呼びます。
F_7* = {1, 2, 3, 4, 5, 6}(0 を除いた 6 個)で、3 のべきを並べます。
3¹ = 3 3² = 9 ≡ 2 3³ = 6 ≡ 6
3⁴ = 18 ≡ 4 3⁵ = 12 ≡ 5 3⁶ = 15 ≡ 1
出てきたのは 3, 2, 6, 4, 5, 1——6 個すべてが 1 回ずつ。
そして 6 乗で 1 に戻り、そこから同じ列を繰り返します。
3 は F₇* の生成元であり、この群は巡回群です。
順番に注目してください。 3, 2, 6, 4, 5, 1 は 大小の順ではありません。⑤ で見たとおり、掛け算は順序を壊します。 この「バラバラさ」が、⑧ の一方向性の材料になります。
同じ F_7* で、今度は 2 のべきを並べます。
2¹ = 2 2² = 4 2³ = 8 ≡ 1 → 以降 2, 4, 1 の繰り返し
2 の位数は 3。到達できるのは {1, 2, 4} の 3 個だけで、
これは F₇* の部分群です。
ラグランジュの定理: 元の位数は必ず群の位数を割り切ります。
6 の約数は 1, 2, 3, 6 なので、F_7* の元の位数は
この 4 通りしかありえません(実際: 1 → 1、6 → 2、2 と 4 → 3、3 と 5 → 6)。
群の位数が素数なら、単位元以外は全部生成元になります——
⑦ の楕円曲線で、この事実がそのまま出てきます。
Week 3 の講義スライドは、フーリエ変換の評価点として 位数 n の 1 の根 ω を使います。定義はこうです。
ωn = 1 かつ ω⁰, ω¹, …, ωn−1 がすべて異なる
これは「ω の位数がちょうど n」と言っているだけです。
スライドの例は F₇ で ω = 2——
上で見た「2 の位数は 3」がそのまま
「2 は位数 3 の 1 の根」になります。
H = {1, ω, ω²} = {1, 2, 4} ⊂ F₇*
同じものに 2 つの名前が付いているだけです。 群の言葉では「位数 3 の元が生成する部分群」、 多項式の言葉では「フーリエ変換の評価点の集合」。 Week 3 以降で多項式を扱うとき、この節に戻れば下地は済んでいます。
F₇* の全元の位数(ラボ A の計算器と同じ結果)
| g | べき乗の列 | 元の位数 | 生成元か |
|---|---|---|---|
| 1 | 1 | 1 | — |
| 2 | 2, 4, 1 | 3 | —(部分群 {1,2,4}) |
| 3 | 3, 2, 6, 4, 5, 1 | 6 | 生成元 |
| 4 | 4, 2, 1 | 3 | — |
| 5 | 5, 4, 6, 2, 3, 1 | 6 | 生成元 |
| 6 | 6, 1 | 2 | — |
位数はすべて 6 の約数(1, 2, 3, 6)に収まっています。
Week 2 の OT ラボが使うトイ群も同じ構造で、F₂₃*(位数 22)の
位数 11 の部分群を使っていました——「なぜ 11 なのか」の答えがラグランジュの定理です。
もう一つの群
ここまでは F_p の中の話でした。楕円曲線は
その体の上に作る、まったく別の群です。
要素は数ではなく「点」、演算は掛け算ではなく「点の足し算」。
それでも群の定義は同じ 4 つです。
体 F_p(p > 3)上の楕円曲線は、次の式を満たす点の集合です。
y² = x³ + a·x + b (a, b ∈ F_p)
ただし、次の条件を満たすものだけを楕円曲線と呼びます。
4a³ + 27b² ≠ 0 (mod p)
これは何の条件か: 右辺 x³ + ax + b が重根を持たない、という条件です。
重根があると曲線に尖った点や自分自身と交わる点ができ、
そこでは接線が 1 本に決まりません。
接線が決まらないと 2 倍算が定義できないので、群になりません。
ラボ B で a = 0, b = 0 を選ぶと、この条件で弾かれる様子が見られます。
方程式を満たす点だけでは群になりません。単位元がないからです。
そこで仮想的な点 O(無限遠点)を 1 つ追加します。
E = {O} ∪ { (x, y) ∈ F_p × F_p | y² = x³ + ax + b }
O は「y 軸方向の無限の彼方」だと思ってください。 すべての垂直線が O を通る、と約束します。 そう約束すると「垂直線も 3 点で交わる」ことになり、 次の加法の定義に例外が要らなくなります。 数学が先で記号が後ではなく、都合のいい点を足して形を整えているのが実際です。
出発点は 1 つの事実です。3 次曲線と直線は、ちょうど 3 点で交わる (接する場合は 2 重に数え、垂直線は O を 3 点目に数える)。
2 点 P, Q を決める → 直線が決まる → 3 点目 R が自動的に決まる
そこで P + Q := −R(R を x 軸に関して反転した点)と定めます。
なぜわざわざ反転するのか: 反転せずに P + Q := R と決めると、
単位元が作れません。
「一直線上の 3 点の和は O」と約束すると、
P + Q + R = O つまり P + Q = −R となり、
O が単位元、x 軸反転が逆元、という群の形にぴたりと収まります。
結合則が成り立つことの証明だけは重く(射影幾何やベズーの定理を使う)、
ここでは事実として使います。
| 群の条件 | 楕円曲線では |
|---|---|
| 閉じている | 3 点目は必ず曲線上(反転しても曲線上:y² は符号に無関係) |
| 結合則 | 成り立つ(証明は重い。ラボ B で総当たり検証している) |
| 単位元 | O。P + O = P |
| 逆元 | −P = (x, −y)。P + (−P) = O |
| 可換 | 成り立つ(P と Q を通る直線は順番によらない) |
「y を反転しても曲線上にある」のは、方程式の左辺が y² だからです。
だから点は必ず上下 2 個ずつペアで現れます——
ラボ B の散布図で、点が中央の線に関して対称に並ぶのはこれが理由です。
例外は y = 0 の点だけで、そこは自分自身が自分の逆元になります。
直線の傾き λ を求めて、3 点目を計算します。場合分けは 2 つだけです。
弦(P ≠ Q): λ = (y₂ − y₁) / (x₂ − x₁)
接線(P = Q): λ = (3x₁² + a) / (2y₁)
x₃ = λ² − x₁ − x₂
y₃ = λ(x₁ − x₃) − y₁
この「/」は有限体の割り算——つまり
(x₂ − x₁)⁻¹ や (2y₁)⁻¹ を掛けることです。
④ で作った逆元が、ここで初めて実戦投入されます。
y₃ の式に注意: λ(x₁ − x₃) − y₁ であって
λ(x₃ − x₁) + y₁ ではありません。
符号の中に「x 軸反転」が畳み込まれています。
Week 3 の課題 README も
「乗らないときは公式のどこか(特に y_R の符号)が間違っています」と警告しています。
① x₁ = x₂ かつ y₁ = −y₂ の場合: 分母 x₂ − x₁ = 0 → P + (−P) = O
② P = Q かつ y₁ = 0 の場合: 分母 2y₁ = 0 → 2P = O
④ の伏線を回収します。
0 に逆元が無いので、この 2 つは「計算できない」のではなく
「結果が O である」と定義するしかありません。
幾何で言えばどちらも垂直線——
② は y = 0 の点での接線が垂直になる場合です。
「0 で割れない」という体の性質が、そのまま群の例外処理になっている。
ラボ B で y² = x³ + x over F₁₁ を選ぶと、
(0, 0) という y = 0 の点が現れます。
これを生成点にすると 2P = O、位数はちょうど 2 です。
手で追う — 2P を計算する
y² = x³ + x + 6 over F₁₁、P = (2, 7) の 2 倍
まず P が曲線上にあるか:
左辺 7² = 49 ≡ 5 右辺 2³+2+6 = 16 ≡ 5 ✓
接線の傾き(分母は 2y = 14):
λ = (3·2² + 1) / (2·7) = 13 / 14
13 ≡ 2、14 ≡ 3 (mod 11)
3⁻¹ ≡ 4 (3·4 = 12 ≡ 1)
λ = 2 · 4 = 8
x₃ = λ² − x₁ − x₂ = 64 − 2 − 2 = 60 ≡ 5
y₃ = λ(x₁ − x₃) − y₁ = 8·(2 − 5) − 7 = −31 ≡ 2
→ 2P = (5, 2)
検算: 左辺 2² = 4、右辺 5³ + 5 + 6 = 136 = 12·11 + 4 ≡ 4 ✓
途中で 2 回、有限体の作法が出ています。
① 13/14 を 2·3⁻¹ に直すところ(先に代表元へ正規化)、
② −31 を 2 に直すところ。
どちらか忘れると、曲線に乗らない点が出て 1 ステップで破綻します。
スカラー倍 — double-and-add
13P を、13 回足さずに 5 回で作る
13 = 8 + 4 + 1 = 1101₂ と分解します。
2P = P + P (doubling 1)
4P = 2P + 2P (doubling 2)
8P = 4P + 4P (doubling 3)
13P = 8P + 4P + P (加算 2 回)
合計 5 回 / 定義どおりなら 12 回
演算回数は k ではなく log₂k に比例します。
k ≈ 2²⁵⁶ でも約 384 回(doubling 256 + 加算 平均 128)で終わります。
Week 3 の課題で必ずここを踏みます。 README にこう書かれています—— 「ec_add を k 回繰り返す実装ではテストが終わりません(テストには k = n ≈ 2²⁵⁶ のケースがあります)」。 素朴な実装は落ちるのではなく、返ってこない。
そして、これが ⑧ の前半分です。
x ↦ xP が速いのは double-and-add があるから。
逆に、その逆をたどる同じくらい速い手が見つかっていない——
この非対称が次の節の主題です。
一方向性
群は定義からして「戻れる」世界でした(逆元があるので)。 にもかかわらず暗号が成立するのは、戻れることと、戻る手が速いことが別だからです。
問題はこう書けます。乗法群の言い方と、楕円曲線の言い方があります。
乗法記法: g と y = gx が与えられたとき、x を求めよ
加法記法: P と Q = xP が与えられたとき、x を求めよ(ECDLP)
速い向きは繰り返し二乗法 / double-and-add で O(log x)。
難しい向きには、いまのところ多項式時間の手がありません。
ハッシュ関数と同じ非対称です。ただし決定的な違いが 1 つ。
ハッシュは情報を捨てているから戻れないのに対して、
離散対数は情報を捨てていません——
x は gx の中に完全に残っていて、
原理的には総当たりで必ず見つかります。
戻れないのではなく、間に合わない。
だから離散対数の安全性は「不可能」ではなく「計算量的に困難」と言います。 Week 2 の秘密分散が「情報理論的に不可能」だったのとは、根拠の強さが違います。 量子計算機の話が出るのはこちら側だけなのも、この違いからです。
2 つの記法は同じことを言っている
| 乗法記法 F_p* | 加法記法 EC | 意味 |
|---|---|---|
| g · h | P + Q | 群演算 |
| 1 | O | 単位元 |
| g⁻¹ | −P | 逆元 |
| gx | xP | x 回の群演算 |
| gx から x | xP から x | 離散対数問題 |
| 繰り返し二乗法 | double-and-add | 速い向きの手 |
記法が違うだけで、群としては同じ話をしています。
EC を使う理由は、同じ安全性を短い鍵で買えるから——
F_p* は 2048 ビット必要なところ、EC なら 256 ビットで済みます
(F_p* には指数計算法という部分的に速い攻撃があり、EC にはそれが効かないため)。
DH 三兄弟を 1 行ずつ
DLP: (P, xP) から x を求めよ。いちばん強い要求。
CDH(計算 Diffie-Hellman):
(P, aP, bP) から abP を作れ。
x を知らなくても共有鍵だけ作れれば破れるので、DLP より弱い要求です。
DDH(判定 Diffie-Hellman):
(P, aP, bP, Z) を見て、Z = abP かランダムか判定せよ。
さらに弱い要求——値を作る必要すらありません。
DLP が解ければ CDH が解け、CDH が解ければ DDH が解ける。
だから安全性の仮定としては逆順に強くなります。 「DDH が難しい」は「DLP が難しい」より強い仮定。 暗号方式は必要な分だけ強い仮定を置きます—— ElGamal の意味論的安全性には DDH が要ります。
小さい群では、暗号は成立しない
次のラボの「離散対数を総当たりで解く」ボタンは、必ず一瞬で当たります。
位数 13 の群なら、試行は最悪 13 回。暗号でも何でもありません。
実用の曲線 secp256k1 の位数は約 2²⁵⁶ ≈ 1.16 × 10⁷⁷——
観測可能な宇宙の原子数(約 10⁸⁰)と同じ桁です。
難しさは群の構造ではなく、位数の大きさが担保しています。
なお総当たりは最悪 n 回ですが、実際の攻撃はPollard のロー法などで
O(√n) まで落ちます。だから 128 ビットの安全性が欲しければ位数は 256 ビット必要——
secp256k1 の 256 ビットという数字は、この平方根から逆算されています。
ラボ B
小さい曲線なら、点は全部数え上げられます。既定は
y² = x³ + x + 6 over F₁₁。
生成点 P を選ぶと 1P, 2P, 3P … を辿って O に戻るところまで見え、
離散対数を総当たりで解くボタンで「小さい群では解けてしまう」ことが確かめられます。
—
—
曲線上の全点(横 = x、縦 = y、破線 = 対称軸 y = p/2)
「x 軸に関して対称」は、mod の世界では y と p − y のペアという意味になります。
図では中央の破線に関して対称に見えます。y = 0 の点だけが相方を持たず、線の下端に単独で並びます。
P の倍々(O に戻るまで)
計算の中身
—
試してほしい設定 1 — 位数が素数の曲線
y² = x³ + x + 6 over F₁₁ は、13 個の点を持つ。
13 は素数なので、ラグランジュの定理から、O 以外のどの点も位数 13 の生成元です。 どの点を選んでも 13 個全部を巡ります。 実用の曲線が「位数が素数(またはほぼ素数)」であることを要求するのは、 部分群に閉じこもる点を作らないためです。
試してほしい設定 2 — y = 0 の点がある曲線
a = 1, b = 0 にすると y² = x³ + x、点は 12 個になる。
この曲線には (0, 0) があります。選んで倍々を見てください——
2P = O で終わり、位数は 2。
⑦ で予告した「分母 2y が 0 になるので O」が、実際に起きています。
位数 12 の群には位数 1, 2, 3, 4, 6, 12 の点が混在します(12 の約数)。
試してほしい設定 3 — 特異曲線
a = 0, b = 0 は弾かれる。
4·0³ + 27·0² = 0 なので滑らかさの条件を満たしません。
y² = x³ は原点に尖点(カスプ)を持ち、そこで接線が決まらない。
「群にならない」ことをラボが拒否として見せます。
p = 11 では (a,b) = (2,3) も特異です
(4·8 + 27·9 = 275 = 25·11 ≡ 0)。
試してほしい設定 4 — 総当たりの試行回数
最悪でも位数と同じ回数で必ず当たる。
p = 17 の曲線でも試行は数十回です。
secp256k1 なら 2²⁵⁶ 通り。
1 秒に 10¹² 回試せる機械を 10 億台並べても、宇宙の年齢では終わりません。
アルゴリズムは同じ、桁だけが違う。
検問クイズ
読んだだけでは定着しません。ここでは正規化・逆元・体の判定・群の性質・楕円曲線の加算を その場で出題します。問題は毎回生成され、判定は上の 2 つのラボと同じ計算器が行います。 3 回間違えたら、その回は終了。
検問モードを選ぶ
誤答するとその場で解説が出る。分野を絞って弱点だけ潰すこともできる。
接続
Week 0 が「数学の準備」に見えて実は伏線だった、という構造になっています。 どこで回収されるかを先に並べておきます。
| 週 | テーマ | Week 0 のどこが効くか |
|---|---|---|
| Week 1 | 算術回路・ZK(proof-of-exploit) | 回路の値が住む場所が F_p。ゲートが + と × だけなのは環の定義。(x−2)(x−5)(x−6)=0 が効くのは零因子が無いから。不等式が書けないのは順序が無いから |
| Week 2 | MPC・秘密計算(toy-mpc) | シェアも Beaver 三つ組も F_p の元。正規化を忘れると採点器に落ちる。シェアの大小から何も漏れないのは順序が無いから。OT のトイ群は F₂₃* の位数 11 の部分群 |
| Week 3 | 楕円曲線と Schnorr(schnorr-from-scratch) | このノートの後半そのもの。Part 1 = 逆元(拡張ユークリッド + 正規化)、Part 2 = 点の加算と double-and-add、Part 3 = 離散対数の困難性の上に建つ署名。講義の方は多項式とフーリエ変換で、位数 n の 1 の根を使う |
| Week 4 以降 | 多項式・コミットメント・KZG | 多項式の係数も評価値も F_p の元。評価点は1 の根の巡回群。KZG のコミットメントは楕円曲線の点で、その安全性は離散対数(と、その強化版)に乗る |
| Week 5 | TFHE(tfhe-toy-python) | 格子ベースなので土台は少し違うが、剰余環の上で乱数に埋めて隠すという発想は Week 2 と同じ形 |
| Week 6 | co-SNARK / zkVM | Beaver 乗算(F_p)と回路(F_p)の合流点。ここまで来ても、値の住む場所は変わらない |
Week 5 だけ土台が少し違いますが、それ以外は全部この 1 ページの上に建っています。
持ち帰る 3 つ
① 順序がない。 だから大小比較は書けず(Week 1 の枷)、大小から秘密は漏れない(Week 2 の武器)。 同じ 1 つの性質が、立つ位置で意味を変えます。
② 割り算は逆元の掛け算。
a⁻¹ は拡張ユークリッドで求め、必ず 0..p−1 に正規化して返す。
そして 0 に逆元は無く、それが楕円曲線の
無限遠点という例外処理の正体でした。
③ 片方向だけ速い。
x ↦ xP は double-and-add で O(log x)、逆は手がない。
ただし「不可能」ではなく「間に合わない」——
ラボ B で総当たりが一瞬で当たったのは、位数が 13 しかなかったからです。
安全性を担保しているのは構造ではなく桁数。
そして、この 3 つの手前に 0 番目があります。 暗号の道具立ては「数学的に美しいから」ではなく、 要求から逆算されて選ばれているということ。 素数を選ぶのは零因子を消すため。有限にするのは固定長で扱うため。 群を使うのは戻れる必要があるため。 「なぜこの形なのか」を毎回聞く癖が、この先いちばん効きます。