# 2025-12-21_"Buggy RSA (my_pow)": 251221 Level: Medium Type: Crypto Solved day: 2025-12-21 ## Solution ### Observation: `my_pow` は「累乗」ではなく加算 `problem.py` の `my_pow(a, n, m)` は繰り返し二乗法を意図しているが、更新式が掛け算ではなく足し算になっている。 - 本来: `result = (result * a) % m` - 実際: `result = (result + a) % m` - 本来: `a = (a * a) % m` - 実際: `a = (a + a) % m` このため、ビット分解した $n$ に対して $a$ を倍々にしながら足し込む「加算的な処理」になり、初期値 $result=1$ が残ることから $$\mathrm{my\_pow}(a, n, m) \equiv 1 + a \cdot n \pmod{m} \quad (n \ge 0)$$ が成立する。 --- ### Apply to encryption 暗号化は $$c = \mathrm{my\_pow}(\mathrm{flag}, e, N)$$ である。よって上の性質から $$ c \equiv 1 + \mathrm{flag} \cdot e \pmod{N} $$ が成り立つ。両辺を整理すると $$ \mathrm{flag} \equiv (c - 1) \cdot e^{-1} \pmod{N} $$ ここで $e^{-1}$ は法 $N$ における $e$ の逆元。 --- ### Recover the flag (given $N, e, c$) `output.txt` より - $N = 1421524\ldots$ - $e = 257$ - $c = 1032307\ldots$ したがって $$ \mathrm{flag} \equiv (c - 1)\, e^{-1} \pmod{N} $$ を計算し、整数からバイト列へ変換すればよい。 ```python # solve.py N = 142152419619953056039030613006300356362328489550709389999387369748296278181079224756839343268342516013642694413617303501060708009652311527189475960379078488611592094334453807443536588862100338035073773947550237167141330041879985706663975671411606265404764401055491939553565105755943917581461262323010934286591 e = 257 c = 1032307400372525030420319173259503709384961767939821142794251896087430140750696054688678035256705431662987859651860033467060026426212901209540363 # flag ≡ (c-1) * e^{-1} (mod N) flag_int = ((c - 1) * pow(e, -1, N)) % N # int -> bytes flag = flag_int.to_bytes((flag_int.bit_length() + 7) // 8, "big") print(flag.decode()) ``` 出力: ``` TSGLIVE{g0od_Mult1plic4t10N-Algor1thm_6y_ru55iAn_Pea5ants} ``` --- ## How I thought ### 重要な観察 1. `my_pow` の更新式が乗算ではなく加算 - `result = (result + a) % m` - `a = (a + a) % m` 2. これは「ビットに応じて倍々の $a$ を足す」加算的処理(Russian peasant multiplication の加算版) 3. 初期値 $result=1$ が残るため $$ \mathrm{my\_pow}(a, n, m) = 1 + a n \pmod{m} \quad (n \ge 0) $$ ### 暗号化が一次式に崩壊 $$ c = \mathrm{my\_pow}(\mathrm{flag}, e, N) \implies c \equiv 1 + \mathrm{flag}\cdot e \pmod{N} \] \[ \therefore\ \mathrm{flag} \equiv (c-1)\cdot e^{-1} \pmod{N} $$ ### 実装上のバグメモ 復号側で `d = my_pow(e, -1, phi)` としているが、`while n > 0` のため $n=-1$ ではループに入らず $1$ を返す。 結果として $d=1$ となり、復号チェックが失敗して `"there is a bug i guess lol"` が出る。