<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Polynomial-Gcd on 万屋猫Labs</title><link>https://yn-labs.com/tags/polynomial-gcd/</link><description>Recent content in Polynomial-Gcd on 万屋猫Labs</description><generator>Hugo</generator><language>ja</language><lastBuildDate>Mon, 13 Jul 2026 11:00:00 +0900</lastBuildDate><atom:link href="https://yn-labs.com/tags/polynomial-gcd/index.xml" rel="self" type="application/rss+xml"/><item><title>KalmarCTF 2026 RBG+ Writeup — 和で隠された RSA を交互和と多項式 GCD で割る</title><link>https://yn-labs.com/writeups/ctf/kalmarctf-2026-rbg-plus-polynomial-gcd/</link><pubDate>Mon, 13 Jul 2026 11:00:00 +0900</pubDate><guid>https://yn-labs.com/writeups/ctf/kalmarctf-2026-rbg-plus-polynomial-gcd/</guid><description>&lt;h2 id="概要"&gt;概要&lt;/h2&gt;
&lt;p&gt;KalmarCTF 2026 の Crypto 問題「RBG+」（106pts）。RSA と LCG（線形合同法）を組み合わせた問題で、フラグ &lt;code&gt;m&lt;/code&gt; が RSA で暗号化され、指数 &lt;code&gt;e&lt;/code&gt; が LCG で更新されていく。厄介なのは、&lt;strong&gt;出力が「2つの暗号文の和」&lt;/strong&gt; として与えられる点だ。2項が足し合わさって個別の &lt;code&gt;m^e mod N&lt;/code&gt; に分離できないため、そのままでは RSA の構造が使えない（値は各項 &lt;code&gt;mod N&lt;/code&gt; の整数和で、和は &lt;code&gt;N&lt;/code&gt; を超えうる。この整数性は後の議論を楽にするが、攻撃の本質は「和で隠されている」ことにある）。&lt;/p&gt;
&lt;p&gt;この「和」をどう剥がすかが核心になる。&lt;/p&gt;
&lt;h2 id="問題の構造"&gt;問題の構造&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;N &lt;span style="color:#f92672"&gt;=&lt;/span&gt; getPrime(&lt;span style="color:#ae81ff"&gt;371&lt;/span&gt;) &lt;span style="color:#f92672"&gt;*&lt;/span&gt; getPrime(&lt;span style="color:#ae81ff"&gt;371&lt;/span&gt;) &lt;span style="color:#75715e"&gt;# 約742-bit RSA modulus（371bit素数2つの積、本インスタンスは742bit）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;e &lt;span style="color:#f92672"&gt;=&lt;/span&gt; getRandomRange(&lt;span style="color:#ae81ff"&gt;731&lt;/span&gt;, N)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(&lt;span style="color:#e6db74"&gt;f&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{&lt;/span&gt;N, e &lt;span style="color:#e6db74"&gt;= }&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;) &lt;span style="color:#75715e"&gt;# N と初期指数 e_0 は出力の1行目で公開される&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lcg &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;lambda&lt;/span&gt; s: (s &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1337&lt;/span&gt;) &lt;span style="color:#f92672"&gt;%&lt;/span&gt; N
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#f92672"&gt;in&lt;/span&gt; range(&lt;span style="color:#ae81ff"&gt;13&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(pow(m, e, N) &lt;span style="color:#f92672"&gt;+&lt;/span&gt; pow(m, e&lt;span style="color:#f92672"&gt;:=&lt;/span&gt;lcg(e), N))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;つまり &lt;strong&gt;&lt;code&gt;N&lt;/code&gt; と初期指数 &lt;code&gt;e_0&lt;/code&gt; は公開値&lt;/strong&gt;（出力の1行目）で、以降 13 行が和 &lt;code&gt;c_i&lt;/code&gt; として与えられる。秘密はフラグ &lt;code&gt;m&lt;/code&gt; だけだ。&lt;/p&gt;</description></item></channel></rss>