Hackenbush에 대한 간단한 튜토리얼을 쓰려고 하는데, 내가 이걸 잘 아는 거는 아니라서 (...) 증명 및 깊이 있는 이론들은 (ordinal 등장 등) 대부분 생략하고 알고리즘 문제 풀이에 써먹을 수 있는 부분들만 간략히 추려서 쓰려고 한다. 자세한 증명은 구글에 검색하면 자료가 매우 많으니 찾아보는 것을 추천한다 :)
Hackenbush 게임은 두 명이서 하는 게임으로, 여러 가지 버전들이 존재하지만 근본적인 목표는 똑같다.
위 그림과 같이, 일종의 그래프가 지면에 연결되어 있는 상태에서 게임이 시작된다.
각 플레이어는 순서대로 간선 하나를 제거하는데, 이때 더 이상 지면에 연결되지 않게 되는 간선들은 모두 삭제된다.
일반적인 룰에서는 (normal play convention) 간선을 제거하지 못하게 되는 플레이어가 패배한다.
간선이 무한히 많은 경우도 존재하지만, 여기에서는 유한한 개수의 간선이 존재한다고 가정한다.
그러면 게임이 확실하게 Sprague-Grundy 방식으로 분석이 가능해진다. 이를 위해서 다음 Principle을 활용한다.
Colon Principle: 그래프 $G, H, K$가 있다. $H, K$의 Grundy 값이 같다면, $G$의 정점 $x$에 $H$를 붙인 그래프와 $x$에 $K$를 붙인 그래프의 Grundy 값이 동일하다. 그러므로, 한 점에서 '가지치기'가 되는 그래프가 있다면, 각 가지들의 Grundy 값의 XOR에 해당하는 길이의 일직선을 붙이는 것으로 가지들을 대체할 수 있다. 이를 통해서 트리 그래프에 대한 분석을 끝낼 수 있다. DFS를 돌면서 서브트리의 Grundy 값을 순서대로 계산하면 된다.
Fusion Principle: 두 정점이 한 사이클 위에 놓인다면 (지면을 하나의 노드로 본다) 두 점을 하나로 합쳐도 Grundy 값이 변하지 않는다.
이때 두 점을 잇는 간선들은 self-loop가 된다. 이 성질을 이용하면, 임의의 그래프에 대한 Grundy 값을 구할 수 있다.
실제로 이를 활용하는 문제는 본 적이 없지만, 아무튼 이를 이용하면 기본 Hackenbush에 대한 분석은 끝이다.
연습문제: Project Euler 400 Fibonacci Tree Game, BOJ 13893 Dictionary Game
두 문제 다 Hackenbush에 대한 이해와 적당한 구현을 (DP/Trie 등) 통해서 해결할 수 있다. Fusion Principle은 필요 없다.
Blue-Red Hackenbush는 조금 색다르다. 이제는 각 간선마다 누가 자를 수 있는지가 둘 중 한 명으로 정해져 있다.
각 플레이어를 Blue/Red라고 하고, Blue 간선은 Blue만, Red 간선은 Red만 자를 수 있도록 한다.
이때는 각 연결 컴포넌트 $G$에 대하여, 그 컴포넌트의 값 $v(G)$를 다음과 같이 재귀적으로 정할 수 있다.
아무것도 없는 그래프의 경우 값은 자명하게 $0$이다. $G$가 nonempty라고 가정하자.
$b$를 Blue가 만들 수 있는 상태 $G'$ 중 $v(G')$의 최댓값이라 하자. 불가능한 경우 $-\infty$.
$r$을 Red가 만들 수 있는 상태 $G'$ 중 $v(G')$의 최솟값이라 하자. 불가능한 경우 $\infty$.
만약 $b < n < r$인 정수 $n$이 존재한다면, $v(G)$는 해당하는 정수 $n$ 중 $0$에 가장 가까운 것이다.
그렇지 않다면, $v(G)$는 $b < x < r$을 만족하는 유리수 $x$ 중 분모가 $2$의 거듭제곱인 것 중에서 분모가 최소인 것이다.
또한, 독립적인 그래프 $G, H$에 대하여 $v(G+H) = v(G) + v(H)$가 성립한다.
만약 $v(G) > 0$이라면 Blue가 승리, $v(G) < 0$이라면 Red가 승리, $v(G)= 0$이라면 후공 승리가 된다.
이 게임에 대한 직관적인 이해를 원한다면 stonejjun의 블로그를 찾아보는 것을 추천한다.
이걸 모두 짬뽕한 Blue-Red-Green Hackenbush도 있는데, 이건 진짜 무서워 보인다 ㅋㅋ
연습문제: BOJ 13409 Black and White Boxes, BOJ 18945 조직된 ㄱ폭탄 게임
13409는 Hackenbush 값을 계산한 다음 Meet In The Middle을 하면 간단하게 해결할 수 있다.
18945는 몇 가지 관찰을 한 다음, 문제를 Blue-Red Hackenbush로 변형하여 해결할 수 있다.
이 글의 진짜 목적 중 하나가 18945의 풀이를 적는 것이니, 여기에 소개한다.
각 게임을 독립적인 Blue-Red Hackenbush 게임으로 보고, 그에 대응하는 값을 계산하자.
그러면 남은 쿼리들은 전부 단순한 point update range query 문제가 되므로, 펜윅/세그먼트 트리를 이용하여 계산할 수 있다.
그러니 문제 난이도의 99%는 각 게임을 Blue-Red Hackenbush 게임으로 변환하는 것에서 나온다.
일반성을 잃지 않고 A 폭탄이 하나 존재한다고 가정하자. 그러면 B 폭탄을 3가지 종류로 나눌 수 있다.
종류 1: A 폭탄이 터지면 강제로 제거되는 B 폭탄들
종류 2: 터뜨리면 A 폭탄이 터지게 되는 B 폭탄들
종류 3: A 폭탄과 서로 interact 할 수 없는 (즉, 하나가 터져도 다른 하나가 터지지 않음) B 폭탄들
이 게임판에서 A가 할 수 있는 행동은 단순히 A 폭탄 하나를 터뜨리는 것 뿐이다.
B가 할 수 있는 행동은 다양한데, 실제로 고려해야 하는 것은 몇 가지 없음을 알 수 있다.
우선 종류 3의 폭탄과 같은 경우에는 애초에 A 폭탄이 터지던 말던 상관이 없기 때문에, 최대한 마지막에 터뜨리는 것이 좋다.
물론, 자신이 터뜨린 폭탄에 의해 자신의 다른 B 폭탄이 쓸데없이 터지지 않도록 순서를 잘 정해서 터뜨려야 한다.
종류 2의 폭탄은 터뜨린다면 강제적으로 종류 1의 폭탄 중 남아있는 것은 무조건 터지게되며, 경우에 따라서 종류 3의 폭탄 역시 터질 수 있다.
그러니 A 폭탄을 제거할 목적으로 종류 2의 폭탄을 터뜨린다면 종류 3의 폭탄을 최소한으로 터뜨리도록 하는 폭탄을 하나 찾아서 그걸 터뜨려야 한다.
종류 1의 폭탄은 터뜨린다면, 다른 종류 1의 폭탄을 터뜨리지 않도록 행/열 순서를 잘 잡아서 순서대로 터뜨려야 한다.
이를 종합하면, 다음과 같은 Blue-Red Hackenbush 그림을 그릴 수 있다. A가 Red, B가 Blue라고 하자.
그래프가 특수한 형태를 가진다. 그러니, 이와 같은 경우에서 Hackenbush 값은 아예 closed form 식을 통해서도 구할 수 있다.
나는 DP를 이용하여 위에서 설명한 규칙을 직접 적용하는 방식으로 구현했다. 분수를 다루기 귀찮으니, 적당히 큰 2의 거듭제곱을 곱해줘서 다루면 편하다.
DP 식 자체는 간단하고, cost 함수인 $\displaystyle \sum_{i=1}^n \left( 1 + \lfloor \log_2 i \rfloor \right)$ 및 실제로 구하고자 하는 값이 $n$에 대하여 볼록함은 쉽게 추측할 수 있고 증명도 수학적 귀납법으로 어렵지 않다. 그런데 $n$ 범위가 $10^{15}$로 매우 높고, 아마도 출제자가 답이 long long int 범위를 넘어가도록 문제를 만들지는 않았을 것이므로, 답이 증가하는 폭이 꽤 작을 것이라고 유추할 수 있다. 즉, 실제로 답의 기울기가 변화하는 점이 적을 것이라고 생각하는 것이다. 이제 기울기가 변화하는 점을 이분탐색/삼분탐색을 잘 섞어서 찾아나가면 된다. 이 아이디어만 잡으면 그 뒤는 어렵지 않은데 아이디어 잡기가 굉장히 어려운 문제인 것 같다.
전형적인 포함-배제를 하듯이, 열심히 계수를 맞춰주면 되는데, 결론적으로 이런 식이 나온다. 검증해보자.
그러면 식이 대충 계산 가능한 다항식이 분자에 있고, $(1-x^t)$ 형태의 식이 분모에 있는 형태가 된다.
그런데 $\displaystyle \frac{1}{1-x} = 1+ x+x^2+ \cdots $를 이용하면 분모를 없애고 식 전체를 생성함수로 전개할 수 있다.
조금 머리를 굴리면, 댓글의 말처럼 뒤에 있는 네 개의 항을 $\mathcal{O}(n^3)$으로 단순 계산을 할 수 있음을 확인할 수 있다.
첫 번째 항인 $A(x)^4$가 약간의 문제가 된다. 이 경우 $\sum_{i=1}^n \left( x^{l_i} - x^{r_i+1} \right) $에 곱해지는 값은 $\displaystyle \frac{1}{(1-x)^4} = \sum_{k=0}^\infty \binom{k+3}{3} x^k$이다.
이제 $\displaystyle P(x) = \sum_{i=1}^n \left( x^{l_i} - x^{r_i+1} \right)$라 하고, 다항식 $f$의 $x^t$의 계수를 $[f]_t$라 하자.
우리가 구하고자 하는 값은 $\displaystyle \sum_{i=0}^s [P(x)^4]_i \binom{s-i+3}{3}$이다. 문제는 역시 $P(x)^4$를 구할 여력이 없다는 점이다.
이 문제를 Vandermonde's Identity로 해결할 수 있다. 우선 $\displaystyle [P(x)^4]_i = \sum_{j=0}^i [P(x)^2]_j [P(x)^2]_{i-j}$라고 써보자.
그러면 우리가 계산해야 하는 것은 $\displaystyle \sum_{i=0}^s \sum_{j=0}^i [P(x)^2]_j [P(x)^2]_{i-j} \binom{s-j-(i-j)+3}{3}$이다.
이제 저 이항 계수를 쪼개고 싶다는 게 명확해지고, $\displaystyle \binom{s-j-(i-j)+3}{3} = \sum_{l=0}^3 \binom{3-j}{l} \cdot \binom{s-(i-j)}{3-l}$로 이를 쪼갤 수 있다.
식을 제대로 쪼개고 나면 문제가 크게 어렵지 않다. $P(x)^2$에 대한 정보를 전부 계산하고, 정렬/부분합이면 된다.
은근 상수도 커서 (특히 $\mathcal{O}(n^3)$ 부분이 조금 상수가 크다) 구현을 나름 섬세하게 해야 했다.
정말 재밌게 푼 문제다. 깔끔하고 아이디어도 좋은 문제. 이 문제는 풀이만 써놓기엔 좀 애매해서 생각 과정도 적는다.
Part 1: 기본적인 관찰
결국 문제의 statement는 각 문제에 대한 아이디어는 시작 후 $0, 1, \cdots t-1$분 후 중 한 시각에 얻어지고, 각 확률이 $1/t$로 동일하며 이는 문제마다 독립적이라는 것이다. 이는 $p \cdot t^n$이 정수인 이유가 되고, 동시에 이 문제가 확률 문제가 아닌 카운팅 문제임을 시사한다.
Part 2: $n$이 작은 경우 직접 계산
우선 $x_1+x_2+ \cdots + x_n > t$인 경우에 답이 $0$임은 자명하다. $n=1$인 경우 답이 $t-x_1+1$임도 자명하다.
$n=2$인 경우를 열심히 계산했고, (이 계산은 어렵지 않다) $(t-x_1-x_2+1)(t-x_2+2)$를 얻었다.
이는 문제의 답이 생각보다 간단한 형태를 가질 거라는 믿음을 나한테 줬다. 도움이 꽤 된듯.
Part 3: $n = t$, $x_1 = x_2 = \cdots = x_n = 1$인 경우
예제 2가 이런 경우고, $n=5$였다. 이때 예제 답이 $1296$이었는데, 이건 $6^4$다.
뭔가 느낌이 쎄해서 $n=2$, $n=3$인 경우를 손으로 계산했는데, 각각 $3^1$, $4^2$가 나왔다.
여기서 나는 답이 $(n+1)^{n-1}$이라고 확신했고, 증명을 고민하기 시작했다. 근데 생각해보니 아는 내용이었다.
이 경우에는 중간에 문제가 바뀌는 걸 고민할 필요가 없다. 시간 안에 아이디어가 공급되는 것만이 중요하다.
각 문제의 아이디어가 나오는 시간을 $t_0, t_1, \cdots , t_{n-1}$이라 하면, 정렬 후 $i$번째 값이 $i$ 이하이면 된다. (0-index)
예전에 $\mathcal{O}(n^2)$ 논문이 있길래 이걸 구현해보려다가 뇌절을 심하게 하고 멘탈 나가서 놓은 문제였다.
풀이는 이 블로그에서도 언급한 EGZ 정리의 증명을 이용한다. 우선 합성수인 경우, 문제를 쪼개서 합칠 수 있다.
$n=ab$라 쓰자. 단, $a, b > 1$. $2ab-1$개의 수가 있을 때, $a$에 대한 문제를 여러 번 풀어 합이 $a$의 배수가 되도록 묶인 $2b-1$개의 그룹으로 만들 수 있다. $2a-1$개의 수를 가지고 합이 $a$의 배수인 그룹을 하나 만들고, 사용되지 않은 수를 다시 써먹는 것을 반복하면 된다.
이제 $2b-1$개의 그룹을 가지고 단순히 $b$에 대한 문제를 풀면 된다. 이는 구현이 귀찮지만 어렵지는 않다.
여기서는 Cauchy-Davenport 정리를 사용한다. 주어진 수를 정렬하여, $0 \le a_1 \le a_2 \le \cdots \le a_{2p-1} < p$라 하자.
이제 $a_i = a_{i+p-1}$인 $i$가 있다면 $i$부터 $i+p-1$을 전부 택하면 합이 자명하게 $p$의 배수가 된다.
그렇지 않다면, 주어진 수를 $\{a_1\}, \{a_2, a_{p+1}\}, \{a_3, a_{p+2}\}, \cdots, \{a_p, a_{2p-1} \}$로 분할하자.
첫 집합을 제외하면, 각 집합의 크기는 (중복 원소가 없으므로) $2$가 된다. 이제 순서대로 Cauchy-Davenport를 쓰면, 각 집합에서 한 원소를 골라서 $p$의 배수를 만들 수 있음을 얻는다. 이를 knapsack과 같은 방법으로 처리하면 끝. 참 멋진 문제라고 생각한다.
Online FFT 테크닉을 이용하여 해결할 수 있는 문제다. 여기서는 이 테크닉을 간단하게 설명한다.
배열 $a$가 주어져 있고, 이때 $c_i = \sum_{j=0}^i a_j a_{i-j}$를 구하고 싶다고 하면, 단순히 FFT를 적용하면 된다.
그런데 만약 $a_i$가 $c_i$와 관련된 값이라던가, 배열 $a$가 바로 주어지지 않고 online으로 주어지면 어떻게 될까?
이때는 단순한 FFT로는 해결하기가 어려우나, 분할 정복을 추가하여 해결할 수 있다.
여기서는 설명의 간단함을 위해 $a_0=0$이라고 가정하고, $c_i = \sum_{j=1}^i a_j a_{i-j}$를 계산해야 $a_i$를 얻을 수 있는 구조라고 생각하자.
카탈란 수의 점화식을 순수하게 FFT 하나로 계산한다고 생각하면 편할 것 같다.
$[L, R)$에 대해서, 문제를 해결하는 재귀함수 $f([L, R))$을 생각해보자. 이때 기본 가정은, 각 $L \le x < R$에 대하여 $a_0, a_1, \cdots, a_{L-1}$의 값을 이미 알고 있으며 각 $L \le t < R$에 대해 $p_L(x)^2 = \left( \sum_{i=0}^{L-1} a_i x^i \right)^2$의 $x^t$ 계수를 저장해놨다고 가정한다.
먼저 $M=(L+R)/2$를 잡고, $f([L, M))$을 호출하자. 이제 $f([M, R))$을 호출할 준비를 해보자.
현재 저장해놓은 $M \le t <R$에 대한 $p_L(x)^2$의 $x^t$의 계수들을 $p_M(x)^2$의 $x^t$의 계수들로 바꿔야 한다.
이는 결국 $(p_M(x)-p_L(x))(p_M(x)+p_L(x))$의 $x^t$ 계수를 구하는 것과 마찬가지다.
$p_M(x)-p_L(x)$는 $L$차 이상 $M$차 미만 단항식들로 구성되어 있다. 또한, 구해야 하는 계수는 최대 $R-1$차이다.
그러니, $p_M(x)+p_L(x)$의 $R-1-L$차 이하 단항식들만 고려해도 충분하다. 그러니 곱해야 하는 두 다항식의 실질적인 차수는 $R-L$에 비례한다. 개인적으로는 $L=0$인 경우를 따로 고려하는 것이 마음이 편하다. 어쨌든 정복 단계라고 볼 수 있는 스텝이 FFT로 $\mathcal{O}((R-L)\log(R-L))$에 된다.
그러니 총 시간복잡도는 $\mathcal{O}(N \log^2 N)$이 된다. 로그 하나는 순수한 분할정복에서 나오므로 꽤 빠르다.
이 문제와 매우 비슷한 형식을 가지고 있는 문제다. 마찬가지로 포함배제를 사용해보자. 편의상 $v_i = b^i - c + 1$이라고 쓴다.
그러면 식이 $\displaystyle \sum_{S \subset \{1,2, \cdots n\}} (-1)^{|S|} \binom{m+n-1-\sum_{i \in S} v_i}{m}$임을 쉽게 확인할 수 있다. 여기까지는 링크의 문제와 같다.
보통 이런 식이 나오면, $\sum_{i \in S} v_i$에 대한 다항식으로 이항계수를 생각하고 싶다.
그런데 여기서는 조합적 해석의 특성상, $a<b$에 대하여 $\binom{a}{b}$를 다항식의 값이 아니라 $0$으로 봐야 한다.
이걸 다루기가 꽤 까다로운데, 앞선 문제에서는 이를 meet in the middle 방식으로 해결했다.
여기서는 $v_i$의 특수한 형식 - 즉 지수적으로 증가하는 형태 - 를 극단적으로 활용할 수 있다.
$dp[i][j][k]$를 $\sum_{S \subset \{1,2, \cdots , i\}, |S|=j} \left( \sum_{t \in S} v_t \right)^k$라고 정의하자. 이는 식을 열심히 전개하여, $\mathcal{O}(m^4)$에 전처리를 할 수 있다.
이제 $\sum_{i \in S} v_i \le m+n-1$인 집합 $S$에 대해서만 다항식의 합을 계산해야 한다. 이는 Digit DP를 하듯이 계산할 수 있다.
큰 "비트"부터 내려가면서, 지금까지 뽑은 것을 봤을 때 나머지를 "자유롭게" 뽑을 수 있다면, 전처리한 DP 값을 활용하여 답을 구할 수 있다.
여기서 $v_i$의 지수적 증가를 활용한다. 전체적으로 문제는 $\mathcal{O}(m^4)$ 시간에 해결되며, 이는 PyPy3으로도 충분히 빠르게 돈다.
감동적으로 좋은 문제. 우선 많은 XOR 문제가 그렇듯이, 비트로 쪼갤 생각을 해야 한다.
$m_1 \ge m_2 \ge \cdots \ge m_n$이라고 하고, $2^t \le m_1 < 2^{t+1}$이 성립한다고 하자. 특히, $m_1$부터 $m_k$가 $2^t$ 이상이고, 나머지는 $2^t$ 미만이라고 하자.
우리는 기본적으로 $2^t$ 비트를 짝수개 뽑아야 한다. $1 \le i \le k$인 $i$에 대하여, $i$번째 변수에서 $2^t$를 뽑는다면 그 변수의 범위는 $2^t$에서 $m_i$가 된다.
그렇지 않는다면, $i$번째 변수는 $0$부터 $2^t-1$까지를 아무거나 뽑아줄 수 있다. 이는 굉장히 강력한 조건이며 이 문제의 핵심이다.
만약 $1 \le i \le k$ 중 $2^t$를 뽑지 않는 $i$가 있다면, 그 $i$를 제외하고 다른 변수들이 $2^t$ 비트만 제대로 맞춰주면 전체 XOR이 $0$이도록 $i$번째 변수의 값을 유일하게 결정할 수 있기 때문이다. 이를 생각하면, "처음으로 $2^t$를 뽑지 않는 index $i$"를 기준으로 카운팅을 해서 답을 얻을 수 있다.
만약 모든 $1 \le i \le k$에 대하여 $2^t$를 뽑는다면, $k$는 짝수여야 하며, $2^t$ 비트를 모두 제거했다고 가정하고 더 작은 문제를 해결하면 된다.
"Twenty Years of Attacks on the RSA Cryptosystem" - Dan Boneh
RSA에 대한 공격을 가장 자세하게 잘 다루는 review paper인 것 같다. 인용 횟수가 900번 근처다...
논문 리딩은 기본적으로 복습을 하면서 더 배우려고 하는 것이기 때문에, 내가 배운 내용도 조금씩 추가하면서 쓰겠다.
또한, Lattice를 제대로 알아야 (특히 LLL) 더욱 자세하게 글을 쓸 수 있을 것으로 보인다. 일단은 맛만 보는 걸로.
#1: Introduction
RSA는 카이사르 암호와 함께 가장 유명한 암호체계 중 하나일 것이다. 1977년 공개된 이 암호체계는 지금도 사용되고 있다.
많이 사용되는 체계인만큼, 많은 암호학자들은 이 체계의 허점을 찾기 위해서 수많은 공격 방법들을 제시해왔다.
공격 방법을 탐구하는 과정을 통해서, 암호학자들은 RSA를 안전하게 구현하고 활용하는 방법을 더욱 알아가게 되었다.
논문의 목적은 이러한 공격들을 돌아보면서, 공격을 위한 수학적 도구에는 어떤 것이 있으며, 이를 막는 방법을 알아보는 것이다.
먼저 Textbook RSA를 살펴보자. $p, q$를 크기가 비슷한 큰 소수라 하고, $N=pq$라 하자. 두 자연수 $e, d$는 $ed \equiv 1 \pmod {\phi(N)}$을 만족하는 자연수다. 여기서 $\phi(N) = (p-1)(q-1)$이다. 이때 $N$을 RSA modulus, $e$를 encryption exponent, $d$를 decryption exponent라고 부른다. $\langle N, e \rangle$은 모두 공개되어 있고 (공개키), 메세지를 암호화하는데 사용할 수 있다. 한편, $\langle N, d \rangle$은 비밀이며 (비밀키), 암호화된 메세지를 받는 사람만이 알고 있다. 메세지를 받는 사람은 비밀키를 이용하여 실제 메세지를 확인할 수 있다. 여기서 메세지란, $M \in \mathbb{Z}_N^{*}$을 말한다. $M$을 암호화하려면, $C \equiv M^e \pmod{N}$을 계산하면 된다.
이를 복호화하려면, $M \equiv C^d \pmod{N}$을 계산하면 된다. 여기서 $ed \equiv 1 \pmod{ \phi(N)}$과 오일러의 정리를 이용한다.
RSA 함수를 $x \rightarrow x^e \pmod{N}$으로 정의하자. $d$를 알면, 이 함수의 역을 쉽게 구할 수 있다.
슬슬 One-Way Function의 느낌이 나온다. 이러한 상황에서, 암호학자들은 $d$를 trapdoor라고 부른다.
trapdoor가 있는 one-way function은 전자서명 등에서 활용될 수 있다. 여기서 RSA의 유용함을 알 수 있다.
메세지 $M$을 내가 보냈다는 것을 인증하려면, 비밀키 $d$를 이용하여 $M^d \pmod{N}$을 사람들에게 주면 된다.
그렇다면, 다른 사람들은 공개키 $e$를 이용하여 $M \equiv (M^d)^e \pmod{N}$, 즉 실제 메세지를 얻는다.
여기서는 $d$에 대한 정보가 없을 때, RSA 함수의 역함수를 계산하는 난이도에 대해서 다루도록 한다.
즉, $N, e, C$가 주어진 경우, $C$의 discrete $e$-th root modulo $N$을 구하는 난이도에 대해 다루는 것이다.
당연히 전수조사의 방법이 있으나, 이는 역시 당연하게도 매우 비효율적이다. 불가능하다고 보는 게 맞겠다.
우리가 관심이 있는 대상은 당연히 실제로 사용될 수 있는 공격들, 특히 다항식 시간을 필요로 하는 공격들이다.
실제 RSA를 이용한 암호체계는 단순한 RSA 함수 응용의 범주를 넘어간다. 안전한 암호가 되려면 빡빡한 기준을 통과해야 한다.
단순하게 RSA 함수를 이용하여 암호화를 하면, 메세지 $M$에 대한 non-trivial information을 손쉽게 얻을 수 있다.
대표적으로, $M$의 modulo $N$에 대한 Jacobi Symbol의 값을 매우 간단하게 얻을 수 있다.
또한, 단순하게 RSA 함수를 이용하여 암호화를 하면 adaptive chosen ciphertext attack에 아주 간단하게 당한다.
복호화를 하고 싶은 $C \equiv M^e \pmod{N}$이 있다고 하자. $2^eC$를 복호화하는 쿼리를 날려보자.
그러면 얻는 답은 $(2^eC)^d \equiv 2C^d \equiv 2M \pmod {N}$이다. 여기서 $M$을 복원하는 것은 쉬운 일이다.
그러니 실제로 RSA를 이용해서 암호화를 하려면, "랜덤함"으로 적당히 간을 쳐서 암호화를 할 필요가 있다. 여기서는 다루지 않는다.
RSA를 사용하기 위해서는, 먼저 큰 소수 $p, q$를 잡는다. 랜덤하게 큰 수를 잡고 적당한 소수 판정법을 쓰면 된다.
그 후 $N = pq$를 얻은 뒤, 적당한 $e$를 잡고 modulo inverse를 계산하는 알고리즘으로 $d$를 계산한다.
물론, 소수는 충분히 많기 때문에, 이러한 방법으로도 RSA key pair를 효율적으로 생성할 수 있다.
RSA를 공격하는 가장 생각하기 쉬운 방법은 사실 그냥 $d$를 찾는 것이다. $d$를 어떻게 찾을 수 있을까?
가장 쉬운 접근은 역시 $\phi(N)$을 찾는 것이다. 그런데 이는 $N$을 소인수분해하는 것과 동치임을 쉽게 파악할 수 있다.
소인수분해가 얼마나 어려운 문제인지는 꽤 잘 알려져 있다. GNFS가 현재까지는 가장 빠르지만, 여전히 느리다.
여기서 우리는 $g^{2^K uvw} \equiv 1 \pmod {N}$이고, $g^{2^{K-1}uvw}$는 우리가 원하는 형태를 갖춤을 알 수 있다.
$k = 2^{2K+C} uvw$이니, 위 알고리즘을 사용하면 우리가 원하는 $g^{2^{K-1}uvw}$를 마주치고 소인수분해에 성공한다.
두 경우 모두에서, 성공 확률이 50% 이상임을 쉽게 파악할 수 있다. 그러니 이를 충분히 반복하면 인수분해에 성공한다.
#2: Elementary Attacks
첫 번째로 살펴볼 것은 메세지 자체가 크기가 작은 경우이다. 만약 $M$이 크기가 작고, 크기가 비슷한 두 자연수의 곱으로 표현될 수 있다고 하자. 이 경우, 간단한 meet-in-the-middle attack을 통해서 메세지를 복원할 수 있다. Key의 크기가 커도 메세지의 크기가 작으면 소용없다는 점을 간과한 경우 발생하는 문제다.
이와 같이 RSA를 잘못 활용한 경우 이를 공격하는 방법을 여기서 더 소개한다.
두 번째로 살펴볼 것은, 모든 사람들에게 공통된 $N$을 사용하게 하는 경우 발생하는 문제점이다.
각 사람들마다 서로 같은 $N$을 주는 대신, 각 사람들에게 $e_i, d_i$를 부여하면 어떻게 될까? (물론, $p, q$는 알려주지 않는다)
다른 사람의 공개키 $e_i$를 봐서 $d_i$를 계산할 수 없으므로 ($p, q$는 모르니까) 이 방법은 잘 먹힐 것처럼 생겼다.
하지만 앞에서 보았듯이, $e_i, d_i, N$을 알면 효율적으로 $N$을 소인수분해 할 수 있다. 그러니 이렇게 하면 나라 망한다.
즉, 모든 사람들이 서로 다른 $N$을 갖도록 해야 안전한 암호체계를 만들 수 있다.
세 번째로 살펴볼 것은, "blinding"이란 것이다. Eve가 Alice에게 메세지 $M \in \mathbb{Z}_N^{*}$에 대한 전자서명을 원한다고 하자.
즉, $M^d \pmod{N}$을 원하는 것이다. 물론 호구가 아닌 이상 Alice가 Eve의 말을 듣고 전자서명을 하지는 않는다.
하지만, Eve가 적당한 $r \in \mathbb{Z}_N^{*}$를 랜덤하게 잡고, $M' \equiv r^eM \pmod{N}$을 계산했다고 하자.
이제 Eve는 Alice에게 $M'$에 대한 전자서명을 부탁한다. Alice는 $r$의 존재도 모르고 그러니 $M$도 모른다.
이제 Alice는 큰 문제가 없게 생긴 $M'$에 대한 전자서명을 줄 수도 있다. 이때, 그 전자서명의 값은 $rM^d \pmod{N}$이 된다.
결국 Eve는 $r$의 modulo inverse를 취해줘서 $M^d \pmod{N}$의 값을 얻게 된다. 전자서명이 뚫린 것이다.
물론, 실제 RSA를 이용한 전자서명이 이렇게 간단하지는 않으므로, 걱정은 하지 않아도 된다.
또한, 논문에 의하면 blinding이 가능하다는 점을 이용하여 "anonymous digital cash"를 구현할 수 있다고 한다.
#3: Low Private Exponent
애초에 작은 $d$ 값을 왜 사용하고 싶어하는 걸까? 이유는 시간에 있다. $d$가 작을수록 decryption에 필요한 시간이 줄어들기 때문이다.
적은 계산 시간은 솔깃하지만, 작은 $d$ 값은 보안성 입장에서 볼 때 매우 위험하다. 다음 공격을 소개한다.
Theorem. (Wiener's Attack) $N = pq$고, $q < p < 2q$라 하자. $d < \frac{1}{3} N^{1/4}$라 하자.
$ed \equiv 1 \pmod{\phi(N)}$인 $N$과 $e < \phi(N)$이 주어졌을 때, $d$를 효율적으로 복원할 수 있다.
앞선 논문 리딩에서도 사용된 연분수를 이용한 rational approximation이 다시 등장한다.
$ed \equiv 1 \pmod{\phi(N)}$이므로, 적당한 $k$가 있어 $ed - k \phi(N) = 1$이다. 그러니, 이를 다시 쓰면 $\displaystyle \left| \frac{e}{\phi(N)} - \frac{k}{d} \right| = \frac{1}{d\phi(N)}$이다.
즉, $\displaystyle \frac{k}{d}$는 $\displaystyle \frac{e}{\phi(N)}$의 근사가 된다. 그런데 $\phi(N)$은 몰라도, $N$은 이미 알고 있다.
또한, $\phi(N) = N -p - q + 1$이고 $p+q-1 < 3 \sqrt{N}$이므로, $|N - \phi(N)| < 3\sqrt{N}$이다.
즉, $\phi(N)$ 대신 $N$을 사용해도 꽤 강력한 근사가 나올 것임을 추측할 수 있다.
그러면 $N_1 , N_2, N_3$가 전부 서로소라고 가정하자. (아니라면, 소인수분해가 간단하게 될 것이다)
이제 중국인의 나머지 정리에서, $M^3 \pmod{N_1N_2N_3}$를 얻을 수 있다. 그런데 $M^3 < N_1N_2N_3$이니, $M$을 얻는다.
이 공격에 대한 간단한 방어를 생각할 수 있다. 각 사람들에게 메세지의 아주 일부를 바꿔서 보내는 것이다.
즉, $i$번째 사람에게 $M^{e_i} \pmod{N_i}$ 대신 $(M+i \cdot 2^m)^{e_i} \pmod{N_i}$를 (물론 $i$와 함께) 보내는 것이다.
여기서 $m$은 $M$의 비트 개수이다. 이 방법은 매우 간단하지만, 위 공격을 막을 수 있을 것으로 보인다.
더욱 일반적으로, 메세지를 전달하고 싶은 사람 $P_1, P_2, \cdots, P_k$가 있을 때, $i$번째 사람에게 $M$을 직접 암호화하는 대신, $f_i \in \mathbb{Z}_{N_i} [x]$를 하나 잡은다음 $f_i(M)$을 암호화하여 (물론, $f_i$와 함께) 보내는 방법을 생각할 수 있다. 이제, Eve가 얻을 수 있는 정보는 다항식 $f_i$와 $e_i, N_i$, $C_i \equiv f_i(M)^{e_i} \pmod{N_i}$이다.
이 상태에서 Eve가 $M$을 도출하는 것은 매우 어려워보인다. 하지만 충분히 많은 정보를 확보하면 가능하다. Coppersmith's Theorem의 위력을 확인해보자.
Theorem. (Hastad's Attack) $N_1, N_2, \cdots , N_k$는 서로소인 자연수이다. $N_{min} = \operatorname{min}(N_1, N_2, \cdots, N_k)$라 하자. 각 $1 \le i \le k$에 대하여, $g_i \in \mathbb{Z}_{N_i}[x]$는 차수가 $d$ 이하인 다항식이라 하자. $g_i(M) \equiv 0 \pmod{N_i}$이 각 $1 \le i \le k$에 대해서 성립하는 $M < N_{min}$이 유일하고, $k>d$가 성립한다고 가정하자. 이때, $1 \le i \le k$에 대하여 $N_i , g_i$를 전부 알 경우 $M$을 다항식 시간에 찾을 수 있다.
먼저, 각 $g_i$가 전부 최고차항의 계수가 $1$임을 가정할 수 있다. $g_i$의 최고차항의 계수가 $N_i$와 서로소가 아니라면, $N_i$를 소인수분해 할 수 있다.
이는 RSA를 다루는 우리의 문맥에서 맞지 않다. 이제 $g_i$의 최고차항의 계수의 modulo inverse를 구해서, $g_i$의 최고차항의 계수를 $1$로 바꿀 수 있다.
또한, $M$이 $N_i$들과 서로소가 아닌 경우 역시 RSA를 다루는 우리의 문맥에 맞지 않다.
그러니, $M$이 $N_i$들과 서로소라고 가정하자. 이러면, $g_i$들에 $x$의 거듭제곱을 적당히 곱해서 모두 차수가 $d$이도록 할 수 있다.
$T_i \equiv \delta_{i, j} \pmod{N_j}$를 만족하는 $T_i$를 CRT로 찾고, $g(x) \equiv \sum_{i=1}^k T_i g_i(x)$를 잡자. $\overline{N} = N_1N_2 \cdots N_k$라 하고, $g(x)$를 $\mathbb{Z}_{\overline{N}}[x]$의 원소로 보자.
$g(x)$의 최고차항의 계수를 각 $i$에 대하여 $\pmod{N_i}$로 보면 $1$임을 확인할 수 있고, 그러니 $g(x)$는 최고차항의 계수가 $1$이다.
또한, $g(x)$의 차수는 $d$이다. 우리가 원하는 $M$은 $g$의 근이며, $M < N_{min} \le \overline{N}^{1/k} < \overline{N}^{1/d}$다.
그러니, $g(x)$와 $\overline{N}$에 대한 Coppersmith's Theorem을 이용하면 $M$을 찾을 수 있다.
그러니 Eve는 $g_i = f_i^{e_i} - C_i$를 잡은 다음, Hastad's Attack을 활용하여 $M$을 복원할 수 있다.
위 정리의 statement를 다시 읽어보면, 이 공격은 $e_i$의 값들이 작을 때 더욱 강력함도 알 수 있다.
실제로 Broadcast Attack에 대한 방어를 하고 싶다면, "랜덤함"으로 적당히 간을 쳐주면 된다고 한다.
두 번째 공격은 Franklin-Reiter Related Message Attack이다. $N, e$가 Alice의 공개키라고 하자.
이제 Bob이 $M_1, M_2 \in \mathbb{Z}_{N}^{*}$를 Alice에게 보내려고 한다.
그런데, 알려진 다항식 $f \in \mathbb{Z}_N [x]$가 있어 $M_1 \equiv f(M_2) \pmod{N}$이 성립한다고 하자.
이제, $C_1, C_2$가 주어졌을 때 Eve가 $M_1, M_2$를 복원할 수 있음을 보일 수 있다.
이 공격은 일반적으로 $\mathcal{O}(e^2)$ 정도의 시간을 필요로 한다고 한다.
일반적인 경우의 증명은 빡센 대수학을 필요로 한다고 하므로, 여기서는 $e=3$이고 $f$가 일차식인 경우를 보인다.
Lemma. $e=3$이라 하고, $N, e$가 RSA를 위한 공개키라고 하자. $M_1 \neq M_2 \in \mathbb{Z}_N^{*}$가 적당한 $f = ax+b \in \mathbb{Z}_N [x]$에 대하여 $M_1 \equiv f(M_2) \pmod{N}$을 만족한다고 하자. 단, $b \neq 0$이다. 이때, $N, e, C_1, C_2, f$를 알면 $M_1, M_2$를 $\mathcal{O}(\log^2 N)$ 시간에 구할 수 있다.
아주 특수한 경우를 다루는 만큼, 증명 역시 크게 어렵지 않다. 먼저 $e$와 관련이 없는 큰 그림을 그려보자.
$M_1 \equiv f(M_2) \pmod{N}$을 알고 있으므로, $M_2$는 $g_1(x) = f(x)^e - C_1 \in \mathbb{Z}_N [x]$의 근이다.
또한, $M_2$는 $g_2(x) = x^e - C_2 \in \mathbb{Z}_N [x]$의 근이기도 하다. 즉, $(x-M_2)$는 $g_1(x), g_2(x)$의 공통 약수다.
그러므로, 유클리드 호제법을 이용하여 $g_1(x), g_2(x)$의 최대공약수를 구한 다음, 그 결과가 일차식이라면 $M_2$를 얻을 수 있다.
Note: 조금 생각을 해보면 유클리드 호제법을 하다가 "문제"가 생기면 $N$의 소인수분해를 얻을 수 있다. 이 점 참고.
특히, $e=3$인 경우에는, 최대공약수가 무조건 일차식이 된다. $g_2(x) = x^3 - C_2$를 생각해보자.
$\text{gcd}(3, \phi(N))=1$이므로, $N=pq$라 할 때 $p, q$는 전부 $2 \pmod{3}$ 형태의 소수이다. 이 경우, $x \rightarrow x^3$은 전단사함수가 된다.
그러므로, $g_2(x) = x^3 - C_2$의 근은 유일하게 존재한다. 즉, $g_2$는 일차식 하나와 irreducible 이차식 하나로 분해된다.
여기서 일차식은 $g_1(x)$와 무조건 공유가 되어야 한다. 공통근이 존재해야 하기 때문이다.
또한, $g_1$과 $g_2$는 서로 나눌 수 없으므로, $g_1$과 $g_2$의 최대공약수는 일차식이 될 수 밖에 없다. 증명 끝.
$e>3$인 경우에는, 최대공약수가 거의 항상 일차식이 되지만, 아닌 경우도 존재한다. 이 경우, 공격은 실패한다.
위 공격을 더욱 강화한 것이 Coppersmith's Short Pad Attack이다. 메세지 $M$에 "랜덤함"으로 간을 해서 암호화를 해야 안전하다고 이미 언급했다.
"랜덤함"으로 간을 하는 가장 간단한 방법은, $M$의 끝에 몇 개의 random bit를 추가하는 것이다.
하지만 이렇게 간을 대충하면 위험하고, 이를 보여주는 것이 Coppersmith's Short Pad Attack이다.
시나리오는 대강 이런 느낌이다. Alice가 Bob에게 메시지 $M$을 전달하려고 한다.
이때 Alice는 $M$의 끝에 몇 개의 random bit를 추가하여 암호화한 다음 Bob에게 전송한다. 이를 Eve가 중간에 연결망을 끊어 Bob이 이를 받지 못하게 한다.
그러면 Alice는 $M$의 끝에 몇 개의 random bit를 다시 추가하여 암호화한 다음 Bob에게 다시 전송하게 될 것이다.
이렇게 되면 Eve는 중간에서 같은 메시지의 (물론, 다른 random bit를 갖는) 암호문을 두 개 확보한다. 이제 Eve는 $M$을 복원할 수 있다.
Theorem. (Coppersmith's Short Pad Attack) $N, e$는 RSA 공개키이고, $N$은 $n$-bit이다. $m=\lfloor n/e^2 \rfloor$라 하자. $M \in \mathbb{Z}_N^{*}$는 길이가 $n-m$ 이하인 메시지이고, $M_1 = 2^m M +r_1$, $M_2 = 2^m M+r_2$라 하자. 이때, $r_1, r_2$는 $0 \le r_1, r_2 < 2^m$을 만족하는 서로 다른 정수다. $N, e$와 $C_1, C_2 \equiv M_1^e, M_2^e \pmod{N}$을 알 때, $M$을 다항식 시간에 얻을 수 있다.
$g_1(x,y) = x^e - C_1$, $g_2(x, y) = (x+y)^e - C_2$라고 하자. 만약 $y = r_2 - r_1$이라면, 두 다항식은 공통근 $M_1$을 갖는다.