picoCTF 2022 Sum-O-Primes を勉強した記録

p+q と p*q が与えられている問題。

800 solves 以上だったので，がんばったが，頑張る方向がヒントの平方根から推理したフェルマー法だった。
p-ｑが1,000,000まで無駄に計算してしまった。

数学が苦手で敬遠したが，本気で
p+q=x
p*q=n
に向き合うと考え方はそこまで難しくなかった。
ただ，pythonで実装する力はなかったので結局は解けなかったと思うが。。。

# 問題

```output.txt
x = 17fef88f46a58da13be8083b814caf6cd8d494dd6c21ad7bf399e521e14466d51a74f51ad5499731018b6a437576e72bd397c4bb07bfbb699c1a35f1f4fa1b86dee2a1702670e9cea45aa7062f9569279d6d4b964f3df2ff8e38cf029faad57e42b831bde21132303e127cba4e80cd3c9ff6a7bad5b399a18252dc35460471ea8
n = 85393637a04ec36e699796ac16979c51ecea41cfd8353c2a241193d1d40d02701b34e9cd4deaf2b13b6717757f178ff75249f3d675448ec928aef41c39e4be1c8ba2ba79c4ada36c607763d7dc8543103acfe1027245acda2208f22fcabe0f37bdadf077e4f943c4f4178cedeb5279a4ebc86323356e23a58b6666ac6ffbf4f1c8229117ffb9071a94dfb724957f10d6664e4ee02e16bed29eb922f126e2082e2f73b5c5b7817e0543155eb9673f4de3de8c91707c1261e8ba6e7348d930293f7796679218c2b1dabe41527eccd72ec3e7284344622eff81ae0541769fb70b6146b54bd092c2dfbe7f8e9653cad80d0fb4f3ef288778927b3852f9ff3a4076d7
c = 42cafbc77ed8396a681dac328701ee02cd746488ae084f15a3e6a5b8f666c595a372a69bbca0dae934fd5ed2292d4393912ee10a22a3b57de9cee2f30b5dc7c67f574b0453f6074171cca37bd407529cb30ba17f152ef5b2484d94b38cf0a513a723255d725e5c3b3f3c985f9223095be3fa148afedf91e4ed37720c3d97dd29cf07830efa8a557a9da68d3095fc3b31f3763e030b62c70d94c3d2951e163e48683f3b9611d562ea06bf1e5d8465e8bf5a6345050a5e7b0c175faf136562cf2a196fdb61ac6503446616cffa9ed85015b86dda73f6eda4d688d3e719a07439d98f95fb5dcf675948ec58d9af83fa29afa4375213ec48f09a6c8cbc431cfe7c6a
```

```python:gen.py
#!/usr/bin/python

from binascii import hexlify
from gmpy2 import mpz_urandomb, next_prime, random_state
import math
import os
import sys

if sys.version_info < (3, 9):
    import gmpy2
    math.gcd = gmpy2.gcd
    math.lcm = gmpy2.lcm

FLAG  = open('flag.txt').read().strip()
FLAG  = int(hexlify(FLAG.encode()), 16)
SEED  = int(hexlify(os.urandom(32)).decode(), 16)
STATE = random_state(SEED)

def get_prime(bits):
    return next_prime(mpz_urandomb(STATE, bits) | (1 << (bits - 1)))

p = get_prime(1024)
q = get_prime(1024)

x = p + q
n = p * q

e = 65537

m = math.lcm(p - 1, q - 1)
d = pow(e, -1, m)

c = pow(FLAG, e, n)

print(f'x = {x:x}')
print(f'n = {n:x}')
print(f'c = {c:x}')
```

p + q = x
p * q = n
が与えられているので，p,qを求める

# 高校数学（数ⅠA）で p , q を解く

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/c351d408-4ae2-3aa7-59b0-e614ca449d0f.png)


二次方程式の解の公式

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/d490ca56-f97e-da95-c777-b67df9a44c2e.png)

つまり，

srv(square root value)　＝　ルート　ｘの２条　－　４ｎ

(x + srv) / 2 = p
(x - srv) / 2 = q

となるはず。

# 実装

```python:test.py
#!/usr/bin/python
from Crypto.Util.number import *
x = 0x17fef88f46a58da13be8083b814caf6cd8d494dd6c21ad7bf399e521e14466d51a74f51ad5499731018b6a437576e72bd397c4bb07bfbb699c1a35f1f4fa1b86dee2a1702670e9cea45aa7062f9569279d6d4b964f3df2ff8e38cf029faad57e42b831bde21132303e127cba4e80cd3c9ff6a7bad5b399a18252dc35460471ea8
n = 0x85393637a04ec36e699796ac16979c51ecea41cfd8353c2a241193d1d40d02701b34e9cd4deaf2b13b6717757f178ff75249f3d675448ec928aef41c39e4be1c8ba2ba79c4ada36c607763d7dc8543103acfe1027245acda2208f22fcabe0f37bdadf077e4f943c4f4178cedeb5279a4ebc86323356e23a58b6666ac6ffbf4f1c8229117ffb9071a94dfb724957f10d6664e4ee02e16bed29eb922f126e2082e2f73b5c5b7817e0543155eb9673f4de3de8c91707c1261e8ba6e7348d930293f7796679218c2b1dabe41527eccd72ec3e7284344622eff81ae0541769fb70b6146b54bd092c2dfbe7f8e9653cad80d0fb4f3ef288778927b3852f9ff3a4076d7
c = 0x42cafbc77ed8396a681dac328701ee02cd746488ae084f15a3e6a5b8f666c595a372a69bbca0dae934fd5ed2292d4393912ee10a22a3b57de9cee2f30b5dc7c67f574b0453f6074171cca37bd407529cb30ba17f152ef5b2484d94b38cf0a513a723255d725e5c3b3f3c985f9223095be3fa148afedf91e4ed37720c3d97dd29cf07830efa8a557a9da68d3095fc3b31f3763e030b62c70d94c3d2951e163e48683f3b9611d562ea06bf1e5d8465e8bf5a6345050a5e7b0c175faf136562cf2a196fdb61ac6503446616cffa9ed85015b86dda73f6eda4d688d3e719a07439d98f95fb5dcf675948ec58d9af83fa29afa4375213ec48f09a6c8cbc431cfe7c6a
e = 65537
p = (x + ((x**2)-(4*n)).sqrt())//2
q = (x - ((x**2)-(4*n)).sqrt())//2
print('p',p)
print('q',q)
assert( p+q == x)
assert( p*q == n)
d = inverse(e, (p-1)*(q-1))
pt = pow(c, d, n)
print(long_to_bytes(pt))
```

結果

```
Traceback (most recent call last):
  File "sol_Sum-O-Primes1.py", line 17, in <module>
    p = (x + ((x**2)-(4*n)).sqrt())//2
AttributeError: 'int' object has no attribute 'sqrt'
```

intはダメらしい

他力本願，よそ様のWriteupを見てみる

https://github.com/elemental-unicorn/picoctf-2022/tree/master/crypto/sum-o-primes

参考サイトを見た後

```python:solver.py
#!/usr/bin/python
from Crypto.Util.number import *
import decimal 
decimal.getcontext().prec = 2000
x = 0x17fef88f46a58da13be8083b814caf6cd8d494dd6c21ad7bf399e521e14466d51a74f51ad5499731018b6a437576e72bd397c4bb07bfbb699c1a35f1f4fa1b86dee2a1702670e9cea45aa7062f9569279d6d4b964f3df2ff8e38cf029faad57e42b831bde21132303e127cba4e80cd3c9ff6a7bad5b399a18252dc35460471ea8
n = 0x85393637a04ec36e699796ac16979c51ecea41cfd8353c2a241193d1d40d02701b34e9cd4deaf2b13b6717757f178ff75249f3d675448ec928aef41c39e4be1c8ba2ba79c4ada36c607763d7dc8543103acfe1027245acda2208f22fcabe0f37bdadf077e4f943c4f4178cedeb5279a4ebc86323356e23a58b6666ac6ffbf4f1c8229117ffb9071a94dfb724957f10d6664e4ee02e16bed29eb922f126e2082e2f73b5c5b7817e0543155eb9673f4de3de8c91707c1261e8ba6e7348d930293f7796679218c2b1dabe41527eccd72ec3e7284344622eff81ae0541769fb70b6146b54bd092c2dfbe7f8e9653cad80d0fb4f3ef288778927b3852f9ff3a4076d7
c = 0x42cafbc77ed8396a681dac328701ee02cd746488ae084f15a3e6a5b8f666c595a372a69bbca0dae934fd5ed2292d4393912ee10a22a3b57de9cee2f30b5dc7c67f574b0453f6074171cca37bd407529cb30ba17f152ef5b2484d94b38cf0a513a723255d725e5c3b3f3c985f9223095be3fa148afedf91e4ed37720c3d97dd29cf07830efa8a557a9da68d3095fc3b31f3763e030b62c70d94c3d2951e163e48683f3b9611d562ea06bf1e5d8465e8bf5a6345050a5e7b0c175faf136562cf2a196fdb61ac6503446616cffa9ed85015b86dda73f6eda4d688d3e719a07439d98f95fb5dcf675948ec58d9af83fa29afa4375213ec48f09a6c8cbc431cfe7c6a
e = 65537
xx = decimal.Decimal(x)
nn = decimal.Decimal(n)
p = (xx + ((xx**2)-(4*nn)).sqrt())//2
q = (xx - ((xx**2)-(4*nn)).sqrt())//2
print('p',p)
print('q',q)
assert( p+q == x)
assert( p*q == n)
d = inverse(e, (p-1)*(q-1))
pt = pow(c, d, n)
print(long_to_bytes(pt))
```

結果

```
(base) E:\picoCTF2022\Sum-O-Primes>python solver.py
p 171605493547460749047153620147807189143153830318479320490789125997400418790068931220714964538131106519997625293387042516388121505143700224886953561940149152974090643943558758253528750845622251033033328825087914744922213112925910051618913976942968425738697927234626842286228129966348756892033903656065084360639
q 98003312109211742492766078547103180302458874375031751582594385856300852883502527670257348847568307704278396061082779143716586619015707011390688920499602751203272333055894471977207396801711910074168795055647226748304769472877973696655496697151190763159772949611427327156924881240093411584911289986786645251817
b'picoCTF{3921def5}'
```

数学から逃げない。
もっと試行錯誤を。
鉛筆で書いてみる。