<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>GNFS on kenji.blog</title><link>http://kenji.blog/tags/gnfs/</link><description>Recent content in GNFS on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>ja</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 05 Sep 2026 13:04:59 +0900</lastBuildDate><atom:link href="http://kenji.blog/tags/gnfs/index.xml" rel="self" type="application/rss+xml"/><item><title>【完全解剖】最強の暗号解読アルゴリズム「GNFS」をC++で実装して理解する</title><link>http://kenji.blog/p/%E5%AE%8C%E5%85%A8%E8%A7%A3%E5%89%96%E6%9C%80%E5%BC%B7%E3%81%AE%E6%9A%97%E5%8F%B7%E8%A7%A3%E8%AA%AD%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0gnfs%E3%82%92c-%E3%81%A7%E5%AE%9F%E8%A3%85%E3%81%97%E3%81%A6%E7%90%86%E8%A7%A3%E3%81%99%E3%82%8B/</link><pubDate>Sat, 05 Sep 2026 13:04:59 +0900</pubDate><guid>http://kenji.blog/p/%E5%AE%8C%E5%85%A8%E8%A7%A3%E5%89%96%E6%9C%80%E5%BC%B7%E3%81%AE%E6%9A%97%E5%8F%B7%E8%A7%A3%E8%AA%AD%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0gnfs%E3%82%92c-%E3%81%A7%E5%AE%9F%E8%A3%85%E3%81%97%E3%81%A6%E7%90%86%E8%A7%A3%E3%81%99%E3%82%8B/</guid><description>&lt;img src="http://kenji.blog/p/%E5%AE%8C%E5%85%A8%E8%A7%A3%E5%89%96%E6%9C%80%E5%BC%B7%E3%81%AE%E6%9A%97%E5%8F%B7%E8%A7%A3%E8%AA%AD%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0gnfs%E3%82%92c-%E3%81%A7%E5%AE%9F%E8%A3%85%E3%81%97%E3%81%A6%E7%90%86%E8%A7%A3%E3%81%99%E3%82%8B/gnfs_cpp_blog_eyecatch_1788580949217.jpg" alt="Featured image of post 【完全解剖】最強の暗号解読アルゴリズム「GNFS」をC++で実装して理解する" />&lt;h1 id="完全解剖最強の暗号解読アルゴリズムgnfsをcで実装して理解する">【完全解剖】最強の暗号解読アルゴリズム「GNFS」をC++で実装して理解する
&lt;/h1>&lt;p>現代のインターネットを根底から支えている「RSA暗号」。その堅牢性は「巨大な合成数を素因数分解することは、現在のコンピュータでは事実上不可能である」という数学的信念に依存しています。&lt;/p>
&lt;p>しかし、人類は決して諦めていません。現在、古典コンピュータ（量子コンピュータではない通常のコンピュータ）において、巨大な素因数分解を行うための &lt;strong>人類最強・最先端のアルゴリズム&lt;/strong> が存在します。それが &lt;strong>「一般数体篩法（GNFS：General Number Field Sieve）」&lt;/strong> です。&lt;/p>
&lt;p>本記事では、このGNFSの最先端の計算ロジックを、C++（Boostライブラリの多倍長整数 &lt;code>boost::multiprecision&lt;/code> を使用）で厳密にモデル化した実装コードを全公開し、その裏側にある「代数的整数論」の深淵を徹底的に解説します。&lt;/p>
&lt;p>数学の神秘と、それをねじ伏せるコンピュータサイエンスの力技を、ぜひソースコードとともに堪能してください。&lt;/p>
&lt;hr>
&lt;h2 id="1-gnfs-最先端ロジックフレームワーク全ソースコード">1. GNFS 最先端ロジック・フレームワーク（全ソースコード）
&lt;/h2>&lt;p>まずは、今回解説するGNFSのC++実装の全貌を掲載します。実際の数体篩法（CADO-NFSなど）は数十万行に及ぶ超巨大な分散システムですが、本コードはGNFSを構成する &lt;strong>「5つの必須パイプライン（フェーズ）」&lt;/strong> を抽出してクラス設計し、数学的な意味を失わずに最小構成でモデル化したものです。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt"> 10
&lt;/span>&lt;span class="lnt"> 11
&lt;/span>&lt;span class="lnt"> 12
&lt;/span>&lt;span class="lnt"> 13
&lt;/span>&lt;span class="lnt"> 14
&lt;/span>&lt;span class="lnt"> 15
&lt;/span>&lt;span class="lnt"> 16
&lt;/span>&lt;span class="lnt"> 17
&lt;/span>&lt;span class="lnt"> 18
&lt;/span>&lt;span class="lnt"> 19
&lt;/span>&lt;span class="lnt"> 20
&lt;/span>&lt;span class="lnt"> 21
&lt;/span>&lt;span class="lnt"> 22
&lt;/span>&lt;span class="lnt"> 23
&lt;/span>&lt;span class="lnt"> 24
&lt;/span>&lt;span class="lnt"> 25
&lt;/span>&lt;span class="lnt"> 26
&lt;/span>&lt;span class="lnt"> 27
&lt;/span>&lt;span class="lnt"> 28
&lt;/span>&lt;span class="lnt"> 29
&lt;/span>&lt;span class="lnt"> 30
&lt;/span>&lt;span class="lnt"> 31
&lt;/span>&lt;span class="lnt"> 32
&lt;/span>&lt;span class="lnt"> 33
&lt;/span>&lt;span class="lnt"> 34
&lt;/span>&lt;span class="lnt"> 35
&lt;/span>&lt;span class="lnt"> 36
&lt;/span>&lt;span class="lnt"> 37
&lt;/span>&lt;span class="lnt"> 38
&lt;/span>&lt;span class="lnt"> 39
&lt;/span>&lt;span class="lnt"> 40
&lt;/span>&lt;span class="lnt"> 41
&lt;/span>&lt;span class="lnt"> 42
&lt;/span>&lt;span class="lnt"> 43
&lt;/span>&lt;span class="lnt"> 44
&lt;/span>&lt;span class="lnt"> 45
&lt;/span>&lt;span class="lnt"> 46
&lt;/span>&lt;span class="lnt"> 47
&lt;/span>&lt;span class="lnt"> 48
&lt;/span>&lt;span class="lnt"> 49
&lt;/span>&lt;span class="lnt"> 50
&lt;/span>&lt;span class="lnt"> 51
&lt;/span>&lt;span class="lnt"> 52
&lt;/span>&lt;span class="lnt"> 53
&lt;/span>&lt;span class="lnt"> 54
&lt;/span>&lt;span class="lnt"> 55
&lt;/span>&lt;span class="lnt"> 56
&lt;/span>&lt;span class="lnt"> 57
&lt;/span>&lt;span class="lnt"> 58
&lt;/span>&lt;span class="lnt"> 59
&lt;/span>&lt;span class="lnt"> 60
&lt;/span>&lt;span class="lnt"> 61
&lt;/span>&lt;span class="lnt"> 62
&lt;/span>&lt;span class="lnt"> 63
&lt;/span>&lt;span class="lnt"> 64
&lt;/span>&lt;span class="lnt"> 65
&lt;/span>&lt;span class="lnt"> 66
&lt;/span>&lt;span class="lnt"> 67
&lt;/span>&lt;span class="lnt"> 68
&lt;/span>&lt;span class="lnt"> 69
&lt;/span>&lt;span class="lnt"> 70
&lt;/span>&lt;span class="lnt"> 71
&lt;/span>&lt;span class="lnt"> 72
&lt;/span>&lt;span class="lnt"> 73
&lt;/span>&lt;span class="lnt"> 74
&lt;/span>&lt;span class="lnt"> 75
&lt;/span>&lt;span class="lnt"> 76
&lt;/span>&lt;span class="lnt"> 77
&lt;/span>&lt;span class="lnt"> 78
&lt;/span>&lt;span class="lnt"> 79
&lt;/span>&lt;span class="lnt"> 80
&lt;/span>&lt;span class="lnt"> 81
&lt;/span>&lt;span class="lnt"> 82
&lt;/span>&lt;span class="lnt"> 83
&lt;/span>&lt;span class="lnt"> 84
&lt;/span>&lt;span class="lnt"> 85
&lt;/span>&lt;span class="lnt"> 86
&lt;/span>&lt;span class="lnt"> 87
&lt;/span>&lt;span class="lnt"> 88
&lt;/span>&lt;span class="lnt"> 89
&lt;/span>&lt;span class="lnt"> 90
&lt;/span>&lt;span class="lnt"> 91
&lt;/span>&lt;span class="lnt"> 92
&lt;/span>&lt;span class="lnt"> 93
&lt;/span>&lt;span class="lnt"> 94
&lt;/span>&lt;span class="lnt"> 95
&lt;/span>&lt;span class="lnt"> 96
&lt;/span>&lt;span class="lnt"> 97
&lt;/span>&lt;span class="lnt"> 98
&lt;/span>&lt;span class="lnt"> 99
&lt;/span>&lt;span class="lnt">100
&lt;/span>&lt;span class="lnt">101
&lt;/span>&lt;span class="lnt">102
&lt;/span>&lt;span class="lnt">103
&lt;/span>&lt;span class="lnt">104
&lt;/span>&lt;span class="lnt">105
&lt;/span>&lt;span class="lnt">106
&lt;/span>&lt;span class="lnt">107
&lt;/span>&lt;span class="lnt">108
&lt;/span>&lt;span class="lnt">109
&lt;/span>&lt;span class="lnt">110
&lt;/span>&lt;span class="lnt">111
&lt;/span>&lt;span class="lnt">112
&lt;/span>&lt;span class="lnt">113
&lt;/span>&lt;span class="lnt">114
&lt;/span>&lt;span class="lnt">115
&lt;/span>&lt;span class="lnt">116
&lt;/span>&lt;span class="lnt">117
&lt;/span>&lt;span class="lnt">118
&lt;/span>&lt;span class="lnt">119
&lt;/span>&lt;span class="lnt">120
&lt;/span>&lt;span class="lnt">121
&lt;/span>&lt;span class="lnt">122
&lt;/span>&lt;span class="lnt">123
&lt;/span>&lt;span class="lnt">124
&lt;/span>&lt;span class="lnt">125
&lt;/span>&lt;span class="lnt">126
&lt;/span>&lt;span class="lnt">127
&lt;/span>&lt;span class="lnt">128
&lt;/span>&lt;span class="lnt">129
&lt;/span>&lt;span class="lnt">130
&lt;/span>&lt;span class="lnt">131
&lt;/span>&lt;span class="lnt">132
&lt;/span>&lt;span class="lnt">133
&lt;/span>&lt;span class="lnt">134
&lt;/span>&lt;span class="lnt">135
&lt;/span>&lt;span class="lnt">136
&lt;/span>&lt;span class="lnt">137
&lt;/span>&lt;span class="lnt">138
&lt;/span>&lt;span class="lnt">139
&lt;/span>&lt;span class="lnt">140
&lt;/span>&lt;span class="lnt">141
&lt;/span>&lt;span class="lnt">142
&lt;/span>&lt;span class="lnt">143
&lt;/span>&lt;span class="lnt">144
&lt;/span>&lt;span class="lnt">145
&lt;/span>&lt;span class="lnt">146
&lt;/span>&lt;span class="lnt">147
&lt;/span>&lt;span class="lnt">148
&lt;/span>&lt;span class="lnt">149
&lt;/span>&lt;span class="lnt">150
&lt;/span>&lt;span class="lnt">151
&lt;/span>&lt;span class="lnt">152
&lt;/span>&lt;span class="lnt">153
&lt;/span>&lt;span class="lnt">154
&lt;/span>&lt;span class="lnt">155
&lt;/span>&lt;span class="lnt">156
&lt;/span>&lt;span class="lnt">157
&lt;/span>&lt;span class="lnt">158
&lt;/span>&lt;span class="lnt">159
&lt;/span>&lt;span class="lnt">160
&lt;/span>&lt;span class="lnt">161
&lt;/span>&lt;span class="lnt">162
&lt;/span>&lt;span class="lnt">163
&lt;/span>&lt;span class="lnt">164
&lt;/span>&lt;span class="lnt">165
&lt;/span>&lt;span class="lnt">166
&lt;/span>&lt;span class="lnt">167
&lt;/span>&lt;span class="lnt">168
&lt;/span>&lt;span class="lnt">169
&lt;/span>&lt;span class="lnt">170
&lt;/span>&lt;span class="lnt">171
&lt;/span>&lt;span class="lnt">172
&lt;/span>&lt;span class="lnt">173
&lt;/span>&lt;span class="lnt">174
&lt;/span>&lt;span class="lnt">175
&lt;/span>&lt;span class="lnt">176
&lt;/span>&lt;span class="lnt">177
&lt;/span>&lt;span class="lnt">178
&lt;/span>&lt;span class="lnt">179
&lt;/span>&lt;span class="lnt">180
&lt;/span>&lt;span class="lnt">181
&lt;/span>&lt;span class="lnt">182
&lt;/span>&lt;span class="lnt">183
&lt;/span>&lt;span class="lnt">184
&lt;/span>&lt;span class="lnt">185
&lt;/span>&lt;span class="lnt">186
&lt;/span>&lt;span class="lnt">187
&lt;/span>&lt;span class="lnt">188
&lt;/span>&lt;span class="lnt">189
&lt;/span>&lt;span class="lnt">190
&lt;/span>&lt;span class="lnt">191
&lt;/span>&lt;span class="lnt">192
&lt;/span>&lt;span class="lnt">193
&lt;/span>&lt;span class="lnt">194
&lt;/span>&lt;span class="lnt">195
&lt;/span>&lt;span class="lnt">196
&lt;/span>&lt;span class="lnt">197
&lt;/span>&lt;span class="lnt">198
&lt;/span>&lt;span class="lnt">199
&lt;/span>&lt;span class="lnt">200
&lt;/span>&lt;span class="lnt">201
&lt;/span>&lt;span class="lnt">202
&lt;/span>&lt;span class="lnt">203
&lt;/span>&lt;span class="lnt">204
&lt;/span>&lt;span class="lnt">205
&lt;/span>&lt;span class="lnt">206
&lt;/span>&lt;span class="lnt">207
&lt;/span>&lt;span class="lnt">208
&lt;/span>&lt;span class="lnt">209
&lt;/span>&lt;span class="lnt">210
&lt;/span>&lt;span class="lnt">211
&lt;/span>&lt;span class="lnt">212
&lt;/span>&lt;span class="lnt">213
&lt;/span>&lt;span class="lnt">214
&lt;/span>&lt;span class="lnt">215
&lt;/span>&lt;span class="lnt">216
&lt;/span>&lt;span class="lnt">217
&lt;/span>&lt;span class="lnt">218
&lt;/span>&lt;span class="lnt">219
&lt;/span>&lt;span class="lnt">220
&lt;/span>&lt;span class="lnt">221
&lt;/span>&lt;span class="lnt">222
&lt;/span>&lt;span class="lnt">223
&lt;/span>&lt;span class="lnt">224
&lt;/span>&lt;span class="lnt">225
&lt;/span>&lt;span class="lnt">226
&lt;/span>&lt;span class="lnt">227
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;cmath&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;map&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;set&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;chrono&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;boost/multiprecision/cpp_int.hpp&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Boost.Multiprecisionの多倍長整数を使用
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">using&lt;/span> &lt;span class="k">namespace&lt;/span> &lt;span class="n">boost&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">multiprecision&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// ============================================================================
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// [SOTA GNFS] General Number Field Sieve (一般数体篩法) 最先端ロジックフレームワーク
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">//
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 本コードは、CADO-NFS等で用いられる最先端のGNFSの5つのパイプラインを
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// C++ (Boost) のクラス設計として厳密にモデル化したものです。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// ============================================================================
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">struct&lt;/span> &lt;span class="nc">Relation&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int64_t&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int64_t&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">uint32_t&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">rational_primes&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">uint32_t&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">algebraic_primes&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// ============================================================================
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Phase 1: Polynomial Selection (KleinJungのアルゴリズム)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// ============================================================================
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">class&lt;/span> &lt;span class="nc">PolynomialSelector&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">degree&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">cpp_int&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// 代数側多項式 f(x)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">cpp_int&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">g&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// 有理側多項式 g(x) = x - m
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PolynomialSelector&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">d&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">degree&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">d&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// base-m 展開を基にした初期多項式の生成 (実際はより高度な格子基底簡約 LLL を使用)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">select&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;[Phase 1] Polynomial Selection (Degree &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">degree&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;) starting...&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 簡易的な base-m 展開 (d次)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// m = N^(1/d)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">N_copy&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">m&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 簡易なmの概算 (Boostの関数を利用しない近似)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">low&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">high&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">low&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="n">high&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">mid&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">low&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">high&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">low&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">degree&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">p&lt;/span> &lt;span class="o">*=&lt;/span> &lt;span class="n">mid&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">p&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">m&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mid&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">low&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mid&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">high&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mid&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">resize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">degree&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">temp&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="n">degree&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">temp&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">temp&lt;/span> &lt;span class="o">/=&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">};&lt;/span> &lt;span class="c1">// g(x) = x - m
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; -&amp;gt; m = &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">m&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; -&amp;gt; f(x) = &amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">degree&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">--&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;x^&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="s">&amp;#34; + &amp;#34;&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">[Phase 1] Complete.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// ============================================================================
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Phase 2: Lattice Sieving (格子篩法)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// ============================================================================
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 近年のGNFSは、Line Sieve（直線篩）ではなく、Franke-Kleinjungらによる
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 特殊q格子篩 (Special-q Lattice Sieving) を用いるのがデファクトスタンダードです。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">class&lt;/span> &lt;span class="nc">LatticeSieve&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint32_t&lt;/span> &lt;span class="n">rational_bound&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint32_t&lt;/span> &lt;span class="n">algebraic_bound&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">uint32_t&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">rational_fb&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">uint32_t&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">algebraic_fb&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">LatticeSieve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">uint32_t&lt;/span> &lt;span class="n">rb&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint32_t&lt;/span> &lt;span class="n">ab&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">rational_bound&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">rb&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">algebraic_bound&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ab&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span> &lt;span class="nf">generate_factor_bases&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;[Phase 2] Generating Factor Bases (Rational Bound: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">rational_bound&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;, Algebraic Bound: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">algebraic_bound&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;)&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// (省略) 実際には素数生成とルジャンドル記号等での絞り込みを行う
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Relation&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">sieve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">PolynomialSelector&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">poly&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;[Phase 2] Special-q Lattice Sieving active...&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Relation&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">relations&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// モック実装: 実際の格子篩は数百GBのメモリ空間をブロック単位でスキャンする
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// (a, b) のペアを特殊素数 q ごとの格子 (a = i*q + j*...) にマッピングし、
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// キャッシュ効率を極限まで高めたシーブ(篩)を実行する。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// デモ用にダミーのリレーションを1つ追加
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Relation&lt;/span> &lt;span class="n">r&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">r&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">17&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">r&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">r&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">rational_primes&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5&lt;/span>&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">r&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">algebraic_primes&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">7&lt;/span>&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">relations&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push_back&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">r&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;[Phase 2] Found &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">relations&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; relations.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">relations&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// ============================================================================
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Phase 3: Filtering (特異点パージとクリークマージ)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// ============================================================================
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">class&lt;/span> &lt;span class="nc">Filter&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span> &lt;span class="n">reduce_matrix&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Relation&lt;/span>&lt;span class="o">&amp;gt;&amp;amp;&lt;/span> &lt;span class="n">relations&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;[Phase 3] Filtering Relations...&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 1. Singleton removal (1度しか出現しない素数を持つリレーションの削除)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// 2. Clique merging (疎な行列を密にするためのリレーション結合)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// 実際にはUnion-Findアルゴリズムなどで数億行の行列を数百万行まで圧縮する。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;[Phase 3] Matrix size reduced optimally.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// ============================================================================
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Phase 4: Linear Algebra over GF(2) (Block Wiedemann 法)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// ============================================================================
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">class&lt;/span> &lt;span class="nc">LinearAlgebraGF2&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 近年のスパコン環境では Block Lanczos 法よりも、分散コンピューティングに
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// 適した Block Wiedemann 法 (Coppersmith実装) が最先端として利用される。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="o">&amp;gt;&amp;gt;&lt;/span> &lt;span class="n">solve_nullspace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Relation&lt;/span>&lt;span class="o">&amp;gt;&amp;amp;&lt;/span> &lt;span class="n">relations&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;[Phase 4] Block Wiedemann algorithm over GF(2) starting...&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// スパース行列(疎行列)とベクトルの積演算を反復し、
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// M * x = 0 mod 2 となる解ベクトル(カーネル)を複数見つける。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="o">&amp;gt;&amp;gt;&lt;/span> &lt;span class="n">dependencies&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// 依存関係のリスト
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// ダミーデータ
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">dependencies&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push_back&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;[Phase 4] Found &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">dependencies&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; linear dependencies (perfect squares).&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">dependencies&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// ============================================================================
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Phase 5: Algebraic Square Root (代数的平方根)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// ============================================================================
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">class&lt;/span> &lt;span class="nc">AlgebraicSquareRoot&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span> &lt;span class="n">compute_and_factor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Relation&lt;/span>&lt;span class="o">&amp;gt;&amp;amp;&lt;/span> &lt;span class="n">relations&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="o">&amp;gt;&amp;amp;&lt;/span> &lt;span class="n">dep&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;[Phase 5] Algebraic Square Root computation...&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 1. 有理側の平方根 V の計算 (単純な整数演算)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">V&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// V = sqrt( prod(a - bm) ) mod N
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 2. 代数側の平方根 gamma の計算 (Montgomery&amp;#39;s method 等)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// 巨大な代数体 O_K の要素 gamma を求め、準同型写像 phi で現実の世界にマッピングする
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// Y = phi(gamma) mod N
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">Y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// イデアル類群と単数群の障害(Obstruction)を回避するため、
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// Phase 2と4で平方剰余指標(Quadratic Characters)の列が追加されている前提。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; -&amp;gt; Homomorphism map phi applied.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;[Phase 5] Calculating GCD(V - Y, N)...&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">factor&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">V&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">Y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// GCD(X-Y, N)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">factor&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">factor&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">================================================================&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;[SUCCESS] Non-trivial factor found: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">factor&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; Other factor: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">N&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">factor&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;================================================================&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;[FAILURE] Trivial solution. Trying next dependency...&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// ============================================================================
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Main Execution Pipeline
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// ============================================================================
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;================================================================&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; [SOTA GNFS] General Number Field Sieve Engine (Boost C++) &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;================================================================&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// RSA-270等、素因数分解したい巨大な合成数 N
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;233108530344407544527637656910680524145619812480305449042948611968495918245135782867888369318577116418213919268572658314913060672626911354027609793166341626693946596196427744273886601876896313468704059066746903123910748277606548649151920812699309766587514735456594993207&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 多項式の次数 (130桁超えの場合は通常 5次〜6次 を選択)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">degree&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// パイプラインの初期化
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">PolynomialSelector&lt;/span> &lt;span class="n">poly_select&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">degree&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">LatticeSieve&lt;/span> &lt;span class="n">sieve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">10000000&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">20000000&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// 実際のバウンドは数千万〜数億
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Filter&lt;/span> &lt;span class="n">filter&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">LinearAlgebraGF2&lt;/span> &lt;span class="n">linalg&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">AlgebraicSquareRoot&lt;/span> &lt;span class="n">sqrt_step&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">auto&lt;/span> &lt;span class="n">start_time&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">chrono&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">high_resolution_clock&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">now&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 1. 多項式選択
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">poly_select&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">select&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">N&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 2. 篩（シーブ）処理
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">sieve&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">generate_factor_bases&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Relation&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">relations&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sieve&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">sieve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">poly_select&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 3. フィルタリング（行列圧縮）
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">filter&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">reduce_matrix&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">relations&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 4. 線形代数（GF(2)上のヌルスペース探索）
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="o">&amp;gt;&amp;gt;&lt;/span> &lt;span class="n">dependencies&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">linalg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">solve_nullspace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">relations&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 5. 代数的平方根の計算とGCD
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="k">auto&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="nl">dep&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">dependencies&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sqrt_step&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">compute_and_factor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">relations&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">dep&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">auto&lt;/span> &lt;span class="n">end_time&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">chrono&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">high_resolution_clock&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">now&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">chrono&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">duration&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">double&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">elapsed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">end_time&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">start_time&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">[System] SOTA GNFS Pipeline completed in &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">elapsed&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">count&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; seconds.&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>それでは、このコードがどのようにして暗号の壁を破壊していくのか。5つのフェーズごとに、その緻密なアルゴリズムと高度な数学をかみ砕いて解説していきます。&lt;/p>
&lt;hr>
&lt;h2 id="2-gnfsの最終目的-x2-equiv-y2-pmod-n">2. GNFSの最終目的： $X^2 \equiv Y^2 \pmod N$
&lt;/h2>&lt;p>GNFSのみならず、現代の巨大素因数分解アルゴリズムのほとんどが目指すゴールは、次の合同式を満たす非自明なペア $(X, Y)$ を見つけることです。&lt;/p>
$$X^2 \equiv Y^2 \pmod N$$
&lt;p>この式は、「$X^2$ と $Y^2$ を $N$ で割った余りが等しい」ことを意味します。これを変形すると、
$X^2 - Y^2 \equiv 0 \pmod N$
つまり、$(X-Y)(X+Y)$ が $N$ の倍数になります。&lt;/p>
&lt;p>もし $X \not\equiv \pm Y \pmod N$ （非自明な解）であれば、$(X-Y)$ と $N$ の間には「1より大きく $N$ より小さい公約数」が存在することになります。
ここで、ユークリッドの互除法を用いて &lt;strong>$\gcd(X-Y, N)$&lt;/strong> を計算すれば、$N$ の素因数がいとも簡単に求まります。&lt;/p>
&lt;p>しかし、この $X$ と $Y$ を見つけるのは砂漠から針を探すようなもの。そこでGNFSは、「現実の整数の世界」と「多項式の代数体の世界」という &lt;strong>2つの世界&lt;/strong> を作り出し、計算を分散させるという天才的なアプローチをとります。&lt;/p>
&lt;hr>
&lt;h2 id="3-phase-1-多項式選択polynomial-selection">3. Phase 1: 多項式選択（Polynomial Selection）
&lt;/h2>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">PolynomialSelector&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">void&lt;/span> &lt;span class="nf">select&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// m = N^(1/d) の計算と base-m 展開
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;=&lt;/span> &lt;span class="n">degree&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">temp&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">temp&lt;/span> &lt;span class="o">/=&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">g&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">m&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">};&lt;/span> &lt;span class="c1">// g(x) = x - m
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>GNFSの最初のステップは、2つの世界を橋渡しするための「魔法の多項式」を作ることです。
巨大な数 $N$ に対して、整数 $m$ を選びます。通常 $m \approx N^{1/d}$ となるように選びます（コード中では $d=6$ 次の多項式を想定）。&lt;/p>
&lt;p>そして、$N$ を $m$ 進数展開し、その係数を使って多項式 $f(x)$ を構築します。
&lt;/p>
$$N = c_d m^d + c_{d-1} m^{d-1} + \dots + c_1 m + c_0$$
$$f(x) = c_d x^d + c_{d-1} x^{d-1} + \dots + c_1 x + c_0$$
&lt;p>この多項式 $f(x)$ には、 &lt;strong>「変数 $x$ に $m$ を代入すると、ちょうど $N$ になる（$f(m) = N$）」&lt;/strong> という極めて重要な性質があります。言い換えれば、$f(m) \equiv 0 \pmod N$ です。
有理側の多項式は $g(x) = x - m$ と定義されます。&lt;/p>
&lt;p>これにより、$f(x)=0$ の根 $\alpha$ が支配する &lt;strong>「代数体の世界 $\mathbb{Z}[\alpha]$」&lt;/strong> と、通常の &lt;strong>「有理数（整数）の世界 $\mathbb{Z}$」&lt;/strong> が、$x \to m$ という「環準同型写像（Homomorphism）」によって強固に結びつけられます。&lt;/p>
&lt;p>最先端のCADO-NFS等では、KleinJungのアルゴリズムやLLL格子基底簡約アルゴリズムを用いて、多項式の係数が極端に大きくならず、かつ後続のステップで素数が出現しやすい（滑らかになりやすい）ような「最高に都合の良い多項式 $f(x)$」を数ヶ月かけて探索します。&lt;/p>
&lt;hr>
&lt;h2 id="4-phase-2-特殊-q-格子篩法special-q-lattice-sieving">4. Phase 2: 特殊 $q$ 格子篩法（Special-q Lattice Sieving）
&lt;/h2>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">LatticeSieve&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Relation&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">sieve&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">PolynomialSelector&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">poly&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// (a, b) のペアを特殊素数 q ごとの格子にマッピングし、
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// キャッシュ効率を極限まで高めたシーブ(篩)を実行する。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>2つの世界を用意したら、次はその両方の世界で「滑らかな数（小さな素数だけで構成される数）」を探すステップに入ります。
整数ペア $(a, b)$ を無数に生成し、以下の2つの値を計算します。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>有理側の値&lt;/strong> ： $a - bm$&lt;/li>
&lt;li>&lt;strong>代数側のノルム&lt;/strong> ： $b^d f(a/b)$&lt;/li>
&lt;/ol>
&lt;p>GNFSの目的は、この &lt;strong>「有理側と代数側の値が、両方とも小さな素因数のみで完全に分解できるペア（Relation：リレーション）」&lt;/strong> を数千万〜数億個集めることです。&lt;/p>
&lt;p>初期のGNFSでは、$(a, b)$ を $xy$ 平面上に並べて端から順に素数で割っていく「直線篩（Line Sieve）」が使われていました。しかし、これではメモリのあちこちへアクセスするためキャッシュミスが多発し、非常に遅いという弱点がありました。&lt;/p>
&lt;p>そこで、現在の最先端コードでは &lt;strong>「特殊 $q$ 格子篩（Special-q Lattice Sieve）」&lt;/strong> という手法が用いられます。
ある適度に大きな素数 $q$ を固定し、「代数側の値が必ず $q$ で割り切れるような $(a, b)$ のペア」だけを計算対象にします。この条件を満たす $(a, b)$ は平面上の「格子（Lattice）」を形成するため、計算するアドレスのジャンプ幅が一定になり、CPUのL1/L2キャッシュに完璧にフィットします。
この格子篩の導入により、GNFSの計算速度は劇的に向上しました。&lt;/p>
&lt;hr>
&lt;h2 id="5-phase-3-フィルタリングfiltering">5. Phase 3: フィルタリング（Filtering）
&lt;/h2>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Filter&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span> &lt;span class="n">reduce_matrix&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Relation&lt;/span>&lt;span class="o">&amp;gt;&amp;amp;&lt;/span> &lt;span class="n">relations&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 1. Singleton removal (1度しか出現しない素数を持つリレーションの削除)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// 2. Clique merging (疎な行列を密にするためのリレーション結合)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Phase 2で世界中のコンピュータが数ヶ月かけて集めた数億個のリレーション。しかし、これをそのまま次の「連立方程式を解くステップ（行列計算）」に投げ込むと、スーパーコンピュータのメモリがパンクしてしまいます。&lt;/p>
&lt;p>そこで &lt;strong>Filtering（フィルタリング）&lt;/strong> と呼ばれる、行列の超圧縮プロセスが行われます。&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Singleton removal（特異点パージ）&lt;/strong>
ある巨大な素数 $p$ が、数億個のリレーションの中で「たった1回」しか登場しなかったとします。私たちが目指すのは「すべての素数の指数を偶数（2の倍数）にすること」ですから、1回しか登場しない素数は絶対に偶数にできません。
したがって、その素数を含むリレーションは「使い道がないゴミ」として即座に削除（パージ）されます。これが連鎖的に起こることで、数億行あったデータがどんどん削られていきます。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Clique merging（クリークマージ）&lt;/strong>
さらに、特定の素数を共有するリレーション同士を掛け合わせる（足し合わせる）ことで、行の数を減らしつつ、疎な（スカスカな）行列をより密な状態へと圧縮します（グラフ理論のクリーク探索に似た手法を用います）。&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>この最適化により、巨大なスパース行列は計算可能なサイズへと劇的に圧縮されます。&lt;/p>
&lt;hr>
&lt;h2 id="6-phase-4-gf2-上の線形代数block-wiedemann法">6. Phase 4: GF(2) 上の線形代数（Block Wiedemann法）
&lt;/h2>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">LinearAlgebraGF2&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="o">&amp;gt;&amp;gt;&lt;/span> &lt;span class="n">solve_nullspace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Relation&lt;/span>&lt;span class="o">&amp;gt;&amp;amp;&lt;/span> &lt;span class="n">relations&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// スパース行列(疎行列)とベクトルの積演算を反復し、
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// M * x = 0 mod 2 となる解ベクトル(カーネル)を複数見つける。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>いよいよ、パズルの核心です。
集めたリレーションを掛け合わせて &lt;strong>「素因数の指数がすべて偶数になる組み合わせ」&lt;/strong> を探します。&lt;/p>
&lt;p>これは数学的には、各素数の指数の「偶数・奇数（つまり0か1）」を要素とする巨大な行列 $M$ と、どのリレーションを使うかを表すベクトル $x$ を用いて、
&lt;strong>$M \cdot x \equiv 0 \pmod 2$&lt;/strong>
となる解ベクトル $x$ （ヌルスペース・カーネル）を求めることに他なりません。&lt;/p>
&lt;p>数百万行 × 数百万列という、とてつもないサイズの行列の連立方程式を解かなければなりません。通常のガウスの消去法では計算量が $O(N^3)$ となり、宇宙が終わるまで計算が終わりません。&lt;/p>
&lt;p>そこで、最先端の実装では &lt;strong>「Block Wiedemann（ブロック・ヴィーデマン）法」&lt;/strong> が採用されています。
これは、行列 $M$ が「非常にスパース（0がほとんど）」であることを利用し、行列とベクトルの掛け算を反復的に行うことで解を導き出すクリロフ部分空間法の一種です。
旧来のBlock Lanczos法と異なり、Block Wiedemann法は計算プロセスを複数のクラスターに完全に分割できるため、現代の分散クラウドコンピューティングやスーパーコンピュータでの並列計算において圧倒的な威力を発揮します。&lt;/p>
&lt;hr>
&lt;h2 id="7-phase-5-代数的平方根algebraic-square-rootと暗号崩壊">7. Phase 5: 代数的平方根（Algebraic Square Root）と暗号崩壊
&lt;/h2>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">AlgebraicSquareRoot&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span> &lt;span class="n">compute_and_factor&lt;/span>&lt;span class="p">(...)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 1. 有理側の平方根 V の計算
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">V&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 2. 代数側の平方根 gamma の計算
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">Y&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">factor&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">gcd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">V&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">Y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">N&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// GCD(X-Y, N)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Phase 4の行列計算により、我々は「掛け合わせるとすべての素因数が偶数乗になるリレーションの集合 $S$」を手に入れました。
これにより、有理側と代数側、それぞれの世界で「2乗」を構築することができます。&lt;/p>
&lt;p>有理側は単なる整数の掛け算なので、平方根 $V$ を計算するのは容易です。
&lt;/p>
$$V^2 = \prod_{S} (a - bm)$$
&lt;p>&lt;strong>しかし、本当の地獄は「代数側」にあります。&lt;/strong>
代数体の世界 $\mathbb{Z}[\alpha]$ では、素因数分解の一意性が成り立たないため、イデアルを用いて計算を行ってきました。行列計算で保証されたのは &lt;strong>「イデアルの2乗」になることだけであり、「要素の2乗（$\gamma^2$）」になることは保証されていない&lt;/strong> のです。&lt;/p>
&lt;p>ここには「イデアル類群の障害」と「単数群の障害」という、代数的整数論における強烈な壁が立ち塞がります。
GNFSでは、この壁を打ち破るために &lt;strong>「平方剰余指標（Quadratic Characters）」&lt;/strong> という魔法を使います。
Phase 4の行列に、あらかじめ数十個の特別な素イデアルに対する平方剰余（ルジャンドル記号）の列をこっそり追加しておくのです。これにより、見つかった集合 $S$ は、圧倒的な確率で障害をスルーし、無事に「真の要素の2乗 $\gamma^2$」を形成してくれます。&lt;/p>
&lt;p>$\gamma$ を求める作業（代数的平方根）は、Montgomery法などの非常に複雑なアルゴリズムを用いて計算されます。&lt;/p>
&lt;p>そしてついに、代数側の平方根 $\gamma$ を、環準同型写像 $\phi$ によって現実の世界にワープ（$x$ に $m$ を代入）させ、$Y$ を得ます。
有理側の $V$ をそのまま $X$ と置けば、ついに追い求めた絶対等式が完成します。&lt;/p>
&lt;p>&lt;strong>$$X^2 \equiv Y^2 \pmod N$$&lt;/strong>&lt;/p>
&lt;p>あとは $\gcd(X-Y, N)$ を計算するだけ。0.001秒の処理が走り抜け、非自明な因数が画面に印字された瞬間、難攻不落を誇ったRSA暗号は完全に崩壊します。&lt;/p>
&lt;hr>
&lt;h2 id="結び">結び
&lt;/h2>&lt;p>GNFSは、単なるプログラミングのテクニックではありません。
抽象代数学、環論、イデアル類群といった「純粋数学の深淵」を、スーパーコンピュータの分散アーキテクチャやキャッシュ最適化といった「極限のエンジニアリング」でねじ伏せた、人類の知性の結晶です。&lt;/p>
&lt;p>私たちが何気なく送信しているチャットやクレジットカードの情報は、このような天文学的な数学の攻防の上に守られているのです。&lt;/p>
&lt;p>このC++フレームワークを通じて、最先端の暗号解読アルゴリズムの裏側にある「数学と計算機のロマン」を感じていただければ幸いです。&lt;/p></description></item><item><title>一般数体篩法（GNFS）の真の数学的構造</title><link>http://kenji.blog/p/%E4%B8%80%E8%88%AC%E6%95%B0%E4%BD%93%E7%AF%A9%E6%B3%95gnfs%E3%81%AE%E7%9C%9F%E3%81%AE%E6%95%B0%E5%AD%A6%E7%9A%84%E6%A7%8B%E9%80%A0/</link><pubDate>Sat, 05 Sep 2026 02:26:13 +0900</pubDate><guid>http://kenji.blog/p/%E4%B8%80%E8%88%AC%E6%95%B0%E4%BD%93%E7%AF%A9%E6%B3%95gnfs%E3%81%AE%E7%9C%9F%E3%81%AE%E6%95%B0%E5%AD%A6%E7%9A%84%E6%A7%8B%E9%80%A0/</guid><description>&lt;img src="http://kenji.blog/p/%E4%B8%80%E8%88%AC%E6%95%B0%E4%BD%93%E7%AF%A9%E6%B3%95gnfs%E3%81%AE%E7%9C%9F%E3%81%AE%E6%95%B0%E5%AD%A6%E7%9A%84%E6%A7%8B%E9%80%A0/rsa_encryption_break_1788542156523.jpg" alt="Featured image of post 一般数体篩法（GNFS）の真の数学的構造" />&lt;h1 id="一般数体篩法gnfsの真の数学的構造">一般数体篩法（GNFS）の真の数学的構造
&lt;/h1>&lt;p>GNFSの究極の目的は、$X^2 \equiv Y^2 \pmod N$ となる $X, Y$ を見つけることです。
これを達成するために、数学者たちは &lt;strong>「現実の整数の世界」&lt;/strong> と &lt;strong>「代数体の世界」&lt;/strong> の間に橋を架けました。その橋こそが「準同型写像」です。&lt;/p>
&lt;h2 id="第1段階世界を繋ぐ準同型写像homomorphism">第1段階：世界を繋ぐ「準同型写像（Homomorphism）」
&lt;/h2>&lt;h3 id="1-多項式の選定と根の定義">1. 多項式の選定と根の定義
&lt;/h3>&lt;p>巨大な合成数 $N$ に対し、ある整数 $m$ と多項式 $f(x)$ を選び、$f(m) \equiv 0 \pmod N$ となるようにします。
（例：$N$ を $m$ 進数展開し、その係数から $f(x)$ を作ります。このとき $f(x)$ は有理数体 $\mathbb{Q}$ 上で既約（これ以上因数分解できない）とします）。&lt;/p>
&lt;p>次に、方程式 $f(x) = 0$ の「複素数における根」の一つを $\alpha$ と置きます。
当然、$f(\alpha) = 0$ です。$\alpha$ は整数ではなく、ルートや虚数を含むような複雑な数（代数的数）です。&lt;/p>
&lt;h3 id="2-環ringと準同型写像の構築">2. 環（Ring）と準同型写像の構築
&lt;/h3>&lt;p>ここで、2つの数学的な「環（足し算と掛け算が定義された世界）」を用意します。&lt;/p>
&lt;ul>
&lt;li>&lt;strong>世界A： $\mathbb{Z}[\alpha]$&lt;/strong> （$\alpha$ を含む代数的な整数の環）
$a + b\alpha + c\alpha^2 + \dots$ という形で表される数の世界です。&lt;/li>
&lt;li>&lt;strong>世界B： $\mathbb{Z}/N\mathbb{Z}$&lt;/strong> （$N$ で割った余りの環）
$0$ から $N-1$ までの整数だけで構成される、合同式（モジュロ）の世界です。&lt;/li>
&lt;/ul>
&lt;p>ここで、世界Aから世界Bへ、次のようなマッピング（写像） $\phi$ を定義します。
&lt;strong>$$\phi : \mathbb{Z}[\alpha] \to \mathbb{Z}/N\mathbb{Z}$$&lt;/strong>
&lt;strong>$$\phi(\alpha) = m \pmod N$$&lt;/strong>&lt;/p>
&lt;p>この写像 $\phi$ は、世界Aの変数 $\alpha$ を、そっくりそのまま世界Bの整数 $m$ にすり替える魔法の操作です。
この $\phi$ は &lt;strong>「環準同型写像（Ring Homomorphism）」&lt;/strong> という極めて強力な性質を持っています。
準同型とは、 &lt;strong>「足し算や掛け算の構造を壊さずに、別の世界へワープさせる」&lt;/strong> 性質のことです。つまり、以下の式が成り立ちます。&lt;/p>
&lt;ul>
&lt;li>$\phi(X \times Y) = \phi(X) \times \phi(Y)$&lt;/li>
&lt;li>$\phi(X^2) = \phi(X)^2$&lt;/li>
&lt;/ul>
&lt;p>これが何を意味するか。もし私たちが「世界A（$\alpha$の世界）」で、何か複雑な要素 $\gamma$ の &lt;strong>「2乗（$\gamma^2$）」&lt;/strong> を作ることができれば、それを $\phi$ で「世界B（余りの世界）」にワープさせても、 &lt;strong>見事に2乗の形 $\phi(\gamma)^2$ が保たれる&lt;/strong> ということです。&lt;/p>
&lt;hr>
&lt;h2 id="第2段階素因数分解の崩壊とイデアルidealの誕生">第2段階：素因数分解の崩壊と「イデアル（Ideal）」の誕生
&lt;/h2>&lt;p>私たちは世界A（$\mathbb{Z}[\alpha]$）の中で、適当な要素 $(a - b\alpha)$ をたくさん集め、それらを掛け合わせて「完全な2乗（平方元）」を作りたいと考えます。
普通なら、集めた $(a - b\alpha)$ をそれぞれ「素因数分解」して、素数の指数がすべて偶数になるように組み合わせ（行列で解く）れば2乗が作れます。&lt;/p>
&lt;p>&lt;strong>しかし、ここで代数学の絶望的な壁が立ちはだかります。&lt;/strong>
$\mathbb{Z}[\alpha]$ のような代数体の世界では、中学で習う &lt;strong>「素因数分解の一意性（どんな数も素数の掛け算でただ1通りに表せる）」が崩壊してしまう&lt;/strong> のです。&lt;/p>
&lt;p>（例：ある代数体の世界では、$6 = 2 \times 3$ であり、同時に $6 = (1+\sqrt{-5}) \times (1-\sqrt{-5})$ となってしまい、どちらが本当の素数か分からなくなります）&lt;/p>
&lt;p>素因数分解が1通りに定まらなければ、「素数の個数を数えて偶数個にする」というパズル（篩法）が原理的に実行できません。&lt;/p>
&lt;h3 id="クンマーとデデキントの救済イデアル">クンマーとデデキントの救済：「イデアル」
&lt;/h3>&lt;p>この崩壊を救ったのが、19世紀の数学者が生み出した &lt;strong>「イデアル（Ideal：理想数）」&lt;/strong> という概念です。
要素そのものではなく、その要素が生成する「倍数の集合（イデアル）」を考えることで、再び素因数分解を可能にしたのです。&lt;/p>
&lt;p>代数体の整数環 $\mathcal{O}_K$（$\mathbb{Z}[\alpha]$ を含むより完全な環）において、要素は一意に素因数分解できなくても、 &lt;strong>「イデアルは必ず『素イデアル（$\mathfrak{p}$）』の積としてただ1通りに素因数分解できる」&lt;/strong> ことが証明されています。&lt;/p>
&lt;p>したがってGNFSでは、要素 $(a - b\alpha)$ そのものを分解するのではなく、それが生成する &lt;strong>単項イデアル $\langle a - b\alpha \rangle$ を素イデアル分解&lt;/strong> します。&lt;/p>
&lt;hr>
&lt;h2 id="第3段階ノルムnormと2つの篩sieve">第3段階：ノルム（Norm）と2つの篩（Sieve）
&lt;/h2>&lt;p>では、イデアル $\langle a - b\alpha \rangle$ がどんな素イデアルに分解されるか、どうやって知るのでしょうか？
ここで &lt;strong>「ノルム（Norm）」&lt;/strong> という関数を使います。ノルムとは、代数体の複雑な要素を「普通の現実の整数 $\mathbb{Z}$」に変換する関数です。&lt;/p>
&lt;p>要素 $(a - b\alpha)$ のノルムは、$b^d f(a/b)$ という簡単な多項式の計算で求まります（$d$ は $f(x)$ の次数）。&lt;/p>
&lt;p>代数的な定理により、 &lt;strong>「あるイデアルのノルムが小さな素数で完全に分解できる（滑らかである）ならば、その元のイデアルも小さな素イデアルで完全に分解できる」&lt;/strong> ことが分かっています。&lt;/p>
&lt;p>そこでGNFSは、大量の整数のペア $(a, b)$ に対して、次の2つを同時に計算し、両方が「滑らかな数」になるペアだけを収集します。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>有理篩（Rational Sieve）&lt;/strong>： $a - bm$ （現実の世界の値）&lt;/li>
&lt;li>&lt;strong>代数篩（Algebraic Sieve）&lt;/strong>： $b^d f(a/b)$ （代数体の世界でのノルム）&lt;/li>
&lt;/ol>
&lt;p>両方が滑らかなペア $(a, b)$ を数千万個集め、イデアルの素因数分解データ（素イデアルが何個含まれているか）を巨大な行列（GF(2)上の線形代数）として解き、「掛け合わせると全ての素イデアルの指数が偶数になる」ようなペアの集合 $S$ を見つけます。&lt;/p>
&lt;hr>
&lt;h2 id="第4段階立ちはだかる2つの障害とイデアル類群">第4段階：立ちはだかる2つの「障害」とイデアル類群
&lt;/h2>&lt;p>行列計算により、集合 $S$ に属する $(a - b\alpha)$ のイデアルをすべて掛け合わせると、あるイデアル $I$ の2乗になることが分かりました。
&lt;/p>
$$\prod_{S} \langle a - b\alpha \rangle = I^2$$
&lt;p>&lt;strong>しかし、まだ終わりません。GNFSにおける最も深く、最も困難な数学の壁がここにあります。&lt;/strong>&lt;/p>
&lt;p>私たちが最後に欲しいのは、「イデアルの2乗」ではなく、写像 $\phi$ に代入するための &lt;strong>「要素の2乗（$\gamma^2$）」&lt;/strong> です。
イデアルの2乗になったからといって、要素自体が2乗になっているとは限らないのです。ここには &lt;strong>2つの強烈な数学的障害（Obstruction）&lt;/strong> が存在します。&lt;/p>
&lt;h3 id="障害イデアル類群ideal-class-groupの壁">障害①：イデアル類群（Ideal Class Group）の壁
&lt;/h3>&lt;p>イデアル $I$ は、必ずしも「1つの要素で生成されるイデアル（単項イデアル）」とは限りません。
単項イデアルではないイデアルから、具体的な要素 $\gamma$ を取り出すことは不可能です。&lt;/p>
&lt;p>ここで &lt;strong>「イデアル類群（Class Group, $Cl_K$）」&lt;/strong> という概念が登場します。イデアル類群とは、「その代数体の世界に、単項イデアルではないイデアルがどれくらい存在するか（素因数分解の一意性がどれくらい壊れているか）」を測る群です。
$\prod \langle a - b\alpha \rangle$ が $I^2$ になったとしても、$I$ がイデアル類群において単位元（単項イデアル）でなければ、要素の2乗に引き戻すことができません。&lt;/p>
&lt;h3 id="障害単数群unit-groupの壁">障害②：単数群（Unit Group）の壁
&lt;/h3>&lt;p>仮に運良く $I$ が単項イデアル $\langle \gamma \rangle$ だったとしましょう。
すると、$\prod \langle a - b\alpha \rangle = \langle \gamma^2 \rangle$ となります。
「よし、要素も2乗だ！」と思うかもしれませんが、大間違いです。&lt;/p>
&lt;p>イデアル（倍数の集合）が等しいということは、要素が完全に等しいことを意味しません。必ず &lt;strong>「単数（Unit：逆数も整数になるような数。1 や -1 など）」&lt;/strong> のズレが生じます。
つまり、実際の要素の等式は次のようになります。
&lt;/p>
$$\prod_{S} (a - b\alpha) = u \cdot \gamma^2$$
&lt;p>
（$u$ は単数群 $U_K$ の要素）&lt;/p>
&lt;p>この単数 $u$ 自体が何かの2乗（平方元）でなければ、左辺は絶対に「完全な要素の2乗」にはなれません。&lt;/p>
&lt;hr>
&lt;h2 id="第5段階アドレマンの魔法平方剰余指標quadratic-characters">第5段階：アドレマンの魔法「平方剰余指標（Quadratic Characters）」
&lt;/h2>&lt;p>イデアル類群の障害と、単数群の障害。この2つをどうやって乗り越えるのか？
ここで、暗号学者レナード・アドレマン（RSAの&amp;quot;A&amp;quot;）らが導入した天才的な手法 &lt;strong>「平方剰余指標（Quadratic Characters）」&lt;/strong> が登場します。&lt;/p>
&lt;p>「ある要素が代数体の中で完全に2乗になっているか？」を判定するために、ルジャンドル記号（平方剰余）の代数体バージョンを使います。
先ほどの巨大な行列（素イデアルの個数を偶数にするためのパズル）に、 &lt;strong>「いくつかの特別な素イデアル $\mathfrak{q}$ に対する平方剰余指標もすべて $1$（偶数）になる」という追加の条件（列）を数十個ほどこっそり付け足す&lt;/strong> のです。&lt;/p>
&lt;p>行列計算によってこの追加条件すらも満たす集合 $S$ を見つけたとき、代数的整数論の深い定理により、 &lt;strong>「イデアル類群の障害も、単数群の障害も、圧倒的な確率で自然に消滅する」&lt;/strong> ことが保証されます。&lt;/p>
&lt;p>これにより、ついに私たちは真の等式を手に入れます。
&lt;/p>
$$\prod_{S} (a - b\alpha) = \gamma^2$$
&lt;hr>
&lt;h2 id="最終段階世界の融合と暗号崩壊">最終段階：世界の融合と暗号崩壊
&lt;/h2>&lt;p>ついにパズルのすべてのピースが揃いました。&lt;/p>
&lt;p>&lt;strong>【代数体の世界（世界A）の要素】&lt;/strong>
$\gamma^2 = \prod (a - b\alpha)$
（これを平方根アルゴリズムを使って $\gamma$ を求めます）&lt;/p>
&lt;p>&lt;strong>【現実の世界（有理数の世界）の要素】&lt;/strong>
$V^2 = \prod (a - bm)$
（こちらは単なる整数の掛け算なので、普通に平方根 $V$ が求まります）&lt;/p>
&lt;p>さあ、一番最初に作った魔法の橋、 &lt;strong>準同型写像 $\phi$&lt;/strong> の出番です。
世界Aの要素 $\gamma$ を、$\phi$（$\alpha$ に $m$ を代入する写像）を使って、世界B（$N$の余りの世界）にワープさせます。
&lt;/p>
$$Y = \phi(\gamma) \pmod N$$
&lt;p>一方、現実の世界で作った $V$ を、そのまま余りの世界に持っていき $X$ とします。
&lt;/p>
$$X = V \pmod N$$
&lt;p>準同型写像の「構造を保つ」性質により、世界Aで成り立っていた2乗の関係は、世界B（モジュロ $N$ の世界）でも完全に保存されています。
さらに、元のペア $(a, b)$ は $a - b\alpha$ と $a - bm$ という形で対応して作られていたため、この $X$ と $Y$ はモジュロ $N$ の世界で激突し、次の絶対的な等式を生み出します。&lt;/p>
&lt;p>&lt;strong>$$X^2 \equiv Y^2 \pmod N$$&lt;/strong>&lt;/p>
&lt;p>あとは、この $X$ と $Y$ が自明な解（$X \equiv \pm Y$）でないことを祈りながら、
&lt;strong>$\gcd(X - Y, N)$&lt;/strong> を計算します。&lt;/p>
&lt;p>非自明な解であれば、ユークリッドの互除法が0.001秒で走り抜け、RSA暗号の心臓部である秘密の素数 $p$ と $q$ が出力画面に印字されます。&lt;/p>
&lt;hr>
&lt;p>これが、現代数学の粋を集めた &lt;strong>「一般数体篩法（GNFS）」の完全な姿&lt;/strong> です。&lt;/p></description></item><item><title>インターネットの暗号を破る人類最強の数学「一般数体篩法（GNFS）」とは？</title><link>http://kenji.blog/p/%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%8D%E3%83%83%E3%83%88%E3%81%AE%E6%9A%97%E5%8F%B7%E3%82%92%E7%A0%B4%E3%82%8B%E4%BA%BA%E9%A1%9E%E6%9C%80%E5%BC%B7%E3%81%AE%E6%95%B0%E5%AD%A6%E4%B8%80%E8%88%AC%E6%95%B0%E4%BD%93%E7%AF%A9%E6%B3%95gnfs%E3%81%A8%E3%81%AF/</link><pubDate>Sat, 05 Sep 2026 02:09:08 +0900</pubDate><guid>http://kenji.blog/p/%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%8D%E3%83%83%E3%83%88%E3%81%AE%E6%9A%97%E5%8F%B7%E3%82%92%E7%A0%B4%E3%82%8B%E4%BA%BA%E9%A1%9E%E6%9C%80%E5%BC%B7%E3%81%AE%E6%95%B0%E5%AD%A6%E4%B8%80%E8%88%AC%E6%95%B0%E4%BD%93%E7%AF%A9%E6%B3%95gnfs%E3%81%A8%E3%81%AF/</guid><description>&lt;img src="http://kenji.blog/p/%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%8D%E3%83%83%E3%83%88%E3%81%AE%E6%9A%97%E5%8F%B7%E3%82%92%E7%A0%B4%E3%82%8B%E4%BA%BA%E9%A1%9E%E6%9C%80%E5%BC%B7%E3%81%AE%E6%95%B0%E5%AD%A6%E4%B8%80%E8%88%AC%E6%95%B0%E4%BD%93%E7%AF%A9%E6%B3%95gnfs%E3%81%A8%E3%81%AF/gnfs_two_worlds_1788542142485.jpg" alt="Featured image of post インターネットの暗号を破る人類最強の数学「一般数体篩法（GNFS）」とは？" />&lt;h1 id="インターネットの暗号を破る人類最強の数学一般数体篩法gnfsとは">インターネットの暗号を破る人類最強の数学「一般数体篩法（GNFS）」とは？
&lt;/h1>&lt;p>私たちが毎日使っているインターネット。LINEのメッセージやYouTube、Amazonでの買い物など、すべての通信は「暗号」によって守られています。
現在、世界中で最も使われている暗号の代表が「RSA暗号」です。&lt;/p>
&lt;p>RSA暗号の守りの要（かなめ）は、非常にシンプルです。それは &lt;strong>「巨大な数の素因数分解は、コンピュータでも解けない」&lt;/strong> という数学の性質を利用していること。
たとえば、「15」なら「3 × 5」とすぐに分かりますが、これが「270桁の数字」になった瞬間、世界中のスーパーコンピュータを束ねても解くのに数億年かかってしまいます。&lt;/p>
&lt;p>しかし、数学者たちも黙ってはいません。この鉄壁の暗号を打ち破るために、人類は &lt;strong>「一般数体篩法（GNFS：General Number Field Sieve）」&lt;/strong> という、魔法のようなアルゴリズム（計算手順）を生み出しました。&lt;/p>
&lt;p>この記事では、専門用語を一切使わず、 &lt;strong>中学校で習う数学（素因数分解、文字式、最大公約数）&lt;/strong> の知識だけで、この「人類最強のアルゴリズム」が暗号を破るカラクリをステップごとに完全解説します！&lt;/p>
&lt;hr>
&lt;h2 id="第1章暗号解読のゴールは中学3年の公式">第1章：暗号解読のゴールは「中学3年の公式」
&lt;/h2>&lt;p>巨大な素因数分解に立ち向かうための最大の必殺技。それは、中学3年生で習うこの公式です。&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>$X^2 - Y^2 = (X + Y)(X - Y)$&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;p>「えっ、こんな基礎的な公式で暗号が破れるの？」と思うかもしれません。しかし、これこそがすべてを解き明かすマスターキーなのです。&lt;/p>
&lt;p>暗号を破るための最大の目標は、巨大な数 $N$ に対して、
&lt;strong>「$X^2$ と $Y^2$ を $N$ で割った余りが同じになる数（$X$ と $Y$）」&lt;/strong> を見つけることです。&lt;/p>
&lt;h3 id="なぜ余りが同じだと暗号が解けるのか">なぜ「余りが同じ」だと暗号が解けるのか？
&lt;/h3>&lt;p>ある2つの数、$X^2$ と $Y^2$ の「$N$ で割った余りが同じ」だとします。
余りが同じということは、 &lt;strong>引き算をした「$X^2 - Y^2$」は、必ず $N$ でピッタリ割り切れる（$N$ の倍数になる）&lt;/strong> という法則があります。&lt;/p>
&lt;p>ここで、暗号に使われる巨大な数 $N$ は、2つの秘密の素数（$p$ と $q$）の掛け算でできているとしましょう（$N = p \times q$）。&lt;/p>
&lt;p>$X^2 - Y^2$ を因数分解すると &lt;strong>$(X - Y)(X + Y)$&lt;/strong> になります。
これが $N$ の倍数であるということは、この掛け算のどこかに、秘密の素数 $p$ と $q$ が隠れているということです。&lt;/p>
&lt;p>ここで奇跡が起きます。
2つの素数 $p$ と $q$ が、 &lt;strong>「$p$ は $(X - Y)$ の部屋へ」「$q$ は $(X + Y)$ の部屋へ」&lt;/strong> と、別々の部屋に分かれて入ってくれる確率が、数学的に &lt;strong>50%（2分の1）&lt;/strong> あるのです。&lt;/p>
&lt;p>素数 $p$ だけが $(X - Y)$ の部屋に入った状態で、$(X - Y)$ と $N$ の &lt;strong>「最大公約数（共通する一番大きな部品）」&lt;/strong> を計算してみましょう。&lt;/p>
&lt;ul>
&lt;li>$(X - Y)$ の中身 ＝ $p \times$ 何かの数&lt;/li>
&lt;li>$N$ の中身 ＝ $p \times q$
共通している部品は &lt;strong>「$p$」&lt;/strong> しかありませんよね！&lt;/li>
&lt;/ul>
&lt;p>つまり、最大公約数を計算した瞬間、隠れていた素数 $p$ がポロッとこぼれ落ち、暗号が完全に解読されてしまうのです。（※最大公約数は「ユークリッドの互除法」を使えば、スマホでも一瞬で計算できます）&lt;/p>
&lt;p>&lt;strong>【ちょっとコラム：なぜ2乗なの？3乗や2倍じゃダメ？】&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>「$2X - 2Y$」だと $2(X - Y)$ になり、部屋が1つしかないので素数を引き離せません。「$X^3 - Y^3$」だと部屋の大きさがアンバランスになり、計算がムダに重くなります。素数を2つに引き離すには、美しく2つの部屋に分かれる「2乗」が一番コスパが良いのです。&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h2 id="第2章xとyをどう探す素数カード集めパズル">第2章：XとYをどう探す？「素数カード集めパズル」
&lt;/h2>&lt;p>ゴールは分かりました。しかし、「余りが同じになる $X^2$ と $Y^2$」を当てずっぽうで探しても、宇宙の寿命が終わるまで見つかりません。
そこで、数学者たちは &lt;strong>「素数カード集めパズル」&lt;/strong> という天才的な方法を思いつきました。&lt;/p>
&lt;h3 id="step-1砂金滑らかな数だけをザルで集める">Step 1：砂金（滑らかな数）だけをザルで集める
&lt;/h3>&lt;p>まず、適当な数 $Z$ を用意し、2乗して $N$ で割った余り $W$ を計算します。
（$Z^2 = W$ の余りの世界）&lt;/p>
&lt;p>出てきた余り $W$ を素因数分解します。ここで、 &lt;strong>「2, 3, 5, 7などの小さな素数だけでできている $W$」&lt;/strong> が出たときだけ、その式を「アタリのカード」として残し、大きな素数が混ざっていたら捨てます。
川で大きな石をザル（ふるい）で捨てて、砂金だけを集めるような作業です。&lt;/p>
&lt;h3 id="step-2全部偶数個にするパズル">Step 2：全部「偶数個」にするパズル
&lt;/h3>&lt;p>たとえば、以下の3枚の砂金カードが集まったとします。&lt;/p>
&lt;ul>
&lt;li>カードA： $Z_1^2 = 2^3 \times 3^1$&lt;/li>
&lt;li>カードB： $Z_2^2 = 2^1 \times 5^1$&lt;/li>
&lt;li>カードC： $Z_3^2 = 3^1 \times 5^1$&lt;/li>
&lt;/ul>
&lt;p>これを全部掛け合わせてみましょう。
右側は $(2^3 \times 3^1) \times (2^1 \times 5^1) \times (3^1 \times 5^1)$ となり、
まとめて整理すると &lt;strong>「$2^4 \times 3^2 \times 5^2$」&lt;/strong> になります。&lt;/p>
&lt;p>なんと、素数の個数が「4個、2個、2個」と、 &lt;strong>すべて偶数個&lt;/strong> になりました！
すべて偶数個ということは、全体を半分の個数にすれば「何かの2乗」になります。
つまり、$(2^2 \times 3^1 \times 5^1)^2 = (60)^2$ です。&lt;/p>
&lt;p>左側は $(Z_1 \times Z_2 \times Z_3)^2$ なので、これでついに、
&lt;strong>$X = (Z_1 \times Z_2 \times Z_3)$&lt;/strong>
&lt;strong>$Y = 60$&lt;/strong>
という、待ちに待った「$X^2 = Y^2$」のペアが完成したのです！&lt;/p>
&lt;p>コンピュータにとって、素数の個数を「偶数か奇数か（0か1か）」で計算するパズルは非常に得意なので、この方法なら高速に $X$ と $Y$ を見つけることができます。&lt;/p>
&lt;hr>
&lt;h2 id="第3章立ちはだかる絶望の壁">第3章：立ちはだかる絶望の壁
&lt;/h2>&lt;p>これでどんな暗号も解ける！……と思いきや、大問題が発生します。
暗号の数字 $N$ が「100桁」くらいまでならこの方法（二次篩法といいます）で解けるのですが、$N$ が「200桁、300桁」になると、計算の途中で出てくる $W$ がデカくなりすぎます。&lt;/p>
&lt;p>数字がデカすぎると、「小さな素数だけでできている数（砂金）」がパッタリと出なくなってしまいます。砂漠でコンタクトレンズを探すよりも難しくなり、パズルを解くためのカードが全く集まらなくなってしまうのです。&lt;/p>
&lt;p>ここでついに、人類の最終兵器 &lt;strong>「一般数体篩法（GNFS）」&lt;/strong> が登場します。&lt;/p>
&lt;hr>
&lt;h2 id="第4章人類最強のアイディア2つの世界を作る">第4章：人類最強のアイディア「2つの世界」を作る
&lt;/h2>&lt;p>GNFSの天才的な発想は、 &lt;strong>「現実の世界だけで計算するから数字がデカくなる。なら、多項式（文字式）を使った『裏の世界』を作って、計算の重さを2つに分散させよう」&lt;/strong> というものです。&lt;/p>
&lt;h3 id="文字式の魔法">文字式の魔法
&lt;/h3>&lt;p>GNFSは、巨大な数 $N$ をベースとなる数 $m$ を使って、文字式に変換します。
たとえば $N=100$ なら、$m=4$ として $100 = 4^3 + 2(4^2) + 4$。
これを文字 $x$ を使って &lt;strong>$f(x) = x^3 + 2x^2 + x$&lt;/strong> という式（裏の世界）にします。&lt;/p>
&lt;p>この式の面白いところは、 &lt;strong>「文字 $x$ に $m$（上の例なら4）を代入すれば、いつでも現実の数 $N$ にワープして戻ってこれる」&lt;/strong> という性質を持っていることです。&lt;/p>
&lt;h3 id="2つの世界で同時に砂金探し">2つの世界で同時に砂金探し
&lt;/h3>&lt;p>GNFSは、適当な整数のペア $(a, b)$ をたくさん作り、次の2つの計算を同時に行います。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>現実の世界&lt;/strong>： $a - b \times m$&lt;/li>
&lt;li>&lt;strong>文字式の世界&lt;/strong>： $a - b \times x$ を文字式のルールで計算した値&lt;/li>
&lt;/ol>
&lt;p>問題を2つの世界に分けたことで、扱う数字のサイズが劇的に小さく（軽く）なります。巨大な岩を2つに割って、扱いやすい石コロにしたイメージです。&lt;/p>
&lt;p>そして、 &lt;strong>「現実の世界でも、文字式の世界でも、両方とも『小さな素数だけでできている（砂金）』」&lt;/strong> という奇跡のペア $(a, b)$ だけをザル（篩：ふるい）でより分けて集めます。これが「数体篩法」という名前の由来です。&lt;/p>
&lt;h3 id="ついに暗号が破れる瞬間">ついに暗号が破れる瞬間
&lt;/h3>&lt;p>両方の世界から数千万枚の「砂金カード」が集まったら、スーパーコンピュータの巨大な行列計算を使って、第2章でやった「素数の個数が全部偶数になる組み合わせ」を見つけ出します。&lt;/p>
&lt;p>組み合わせが見つかったら、&lt;/p>
&lt;ul>
&lt;li>現実の世界でできた2乗の数を &lt;strong>$X^2$&lt;/strong>&lt;/li>
&lt;li>文字式の世界でできた2乗の式を &lt;strong>$Y(x)^2$&lt;/strong> とします。&lt;/li>
&lt;/ul>
&lt;p>最後に、文字式の $Y(x)$ の $x$ に $m$ を代入し、現実の世界にワープさせて合流させます。
すると、数学の魔法のように &lt;strong>「$X^2$ と $Y^2$ の余りが同じになる」&lt;/strong> という状態が厳密に完成するのです！&lt;/p>
&lt;p>あとは第1章の通り、$X - Y$ と $N$ の最大公約数を計算すれば、難攻不落のRSA暗号は音を立てて崩れ去り、秘密の素数が姿を現します。&lt;/p>
&lt;hr>
&lt;h2 id="おわりに数学は終わらない">おわりに：数学は終わらない
&lt;/h2>&lt;p>「よし、GNFSを使えばどんな暗号も破れるんだな！」と思ったかもしれません。
しかし、RSA暗号も負けていません。現在のインターネットで使われているのは「RSA-2048（約617桁）」というバケモノのような巨大数です。&lt;/p>
&lt;p>GNFSがいかに人類最強のアルゴリズムとはいえ、270桁（RSA-270）を解くのにすら、世界中のコンピュータを繋いでも数千年、数万年かかると言われています。今のところ、私たちのLINEや銀行のデータは安全です。&lt;/p>
&lt;p>しかし、もし &lt;strong>「どんな巨大な数でも一瞬で $X$ と $Y$ を見つける魔法」&lt;/strong> が現れたらどうなるでしょうか？
実は、それに最も近い存在が現在開発中の &lt;strong>「量子コンピュータ（ショアのアルゴリズム）」&lt;/strong> です。量子力学の波の性質を使えば、面倒なカード集めパズルを無視して、一発で答えを引き当てることができると数学的に証明されています。&lt;/p>
&lt;p>暗号を作る人（防御）と、暗号を破るアルゴリズムを作る人（攻撃）の果てしない知恵比べ。
中学校で習う「素因数分解」や「文字式」が、実は世界のセキュリティの最前線でバチバチに戦っている武器だと知ると、少しだけ数学の授業が面白く見えてきませんか？&lt;/p>
&lt;p>未来の最強アルゴリズムを発見するのは、この記事を読んでいるあなたかもしれません！&lt;/p>
&lt;hr>
&lt;p>&lt;em>(※本記事は、暗号解読の数学的魅力を中学生向けに概念化したものです。実際のGNFSは、代数体のイデアル類群や準同型写像などの高度な大学数学を用いて厳密に計算されています)&lt;/em>&lt;/p></description></item></channel></rss>