문제 정보
문제 링크: https://www.acmicpc.net/problem/13618
문제 요약: 정수 N, E, C가 주어진다. 여기서 (N, E)는 RSA 공개키이고, C는 이 공개키로 암호화된 메시지이다. N을 두 소수 p, q로 소인수분해한 뒤 오일러 피 함수 φ(N) = (p-1)(q-1)를 계산하고, E의 모듈러 역원 d를 구해 M = C^d mod N을 복호화한 값을 출력해야 한다.
제한 조건: (공식 페이지 기준)
- 시간 제한: 1초
- 메모리 제한: 128MB
- 입력:
N,E,C(범위는 RSA 복호를 단순 정수형으로 처리 가능한 수준)
입출력 예제
문제 페이지에 제시된 예제를 그대로 옮기지 않고, 형식을 맞추기 위해 간단한 예시 형태만 정리합니다.
입력 예시 형태:
| |
출력 예시 형태:
| |
여기서 M은 복호화된 원문 정수입니다.
접근 방식
핵심 관찰
- RSA 복호 공식은 \(M \equiv C^d \pmod{N}\)이며, 여기서 \(d\)는 \(E d \equiv 1 \pmod{\varphi(N)}\)을 만족하는 모듈러 역원이다.
- \(N = p q\) (서로 다른 두 소수)라고 할 때 \(\varphi(N) = (p-1)(q-1)\) 이므로, 먼저
N을 소인수분해해야 한다. - \(\gcd(E, \varphi(N)) = 1\) 이므로, 확장 유클리드 알고리즘으로 \(E\)에 대한 \(\varphi(N)\) 모듈러 역원 \(d\)를 구할 수 있다.
- 마지막으로 **반복 제곱법(이분 거듭제곱)**으로 \(C^d \bmod N\)을 계산하면 되며, 곱셈 과정에서 오버플로가 나지 않도록 타입과 연산에 주의해야 한다.
알고리즘 설계 (Mermaid)
flowchart TD
A[입력 N, E, C] --> B[소인수분해로 p, q 찾기]
B --> C["phi 계산: (p-1)*(q-1)"]
C --> D[확장 유클리드로 d 계산]
D --> E["모듈러 거듭제곱으로 M = C^d mod N"]
E --> F[정수 M 출력]
단계별 로직
소인수분해
i = 2부터 시작해서i * i <= N범위에서 나누어 떨어지는 첫 약수를 찾는다.N % i == 0인i를 찾으면p = i,q = N / i로 두 소수를 얻는다.
φ(N) 계산
phi = (p - 1) * (q - 1)을 정수형 범위에서 계산한다.
d (개인키 지수) 계산
- 확장 유클리드 알고리즘으로
E * x + phi * y = gcd(E, phi) = 1을 만족하는(x, y)를 구한다. - 이때
x가E의 모듈러 역원 후보이므로,d = (x % phi + phi) % phi로 정규화한다.
- 확장 유클리드 알고리즘으로
모듈러 거듭제곱으로 복호화
- 반복 제곱법으로
M = C^d mod N을 계산한다. - 곱셈 과정에서 오버플로가 우려된다면
__int128을 사용한 안전한 모듈러 곱셈으로 보강할 수 있다.
- 반복 제곱법으로
출력
- 최종적으로 얻은
M을 그대로 출력한다.
- 최종적으로 얻은
복잡도 분석
| 항목 | 복잡도 | 비고 |
|---|---|---|
| 시간 복잡도 | \(O(\sqrt{N} + \log d)\) | 소인수분해 \(O(\sqrt{N})\), 모듈러 거듭제곱 \(O(\log d)\) |
| 공간 복잡도 | \(O(1)\) | 입력과 상수 개수의 변수만 사용 |
구현 코드
C++
| |
코너 케이스 및 실수 포인트
| 케이스 | 설명 | 처리 방법 |
|---|---|---|
| N이 두 소수의 곱 | 문제에서는 RSA 구조를 가정 | 약수 탐색 중 첫 약수 i를 찾으면 바로 p, q로 사용 |
| gcd(E, φ(N)) = 1 | 역원이 항상 존재해야 함 | 확장 유클리드 알고리즘으로 역원 계산, 문제 보장 전제 활용 |
| 오버플로 위험 | C^d는 직접 계산 불가 | 반복 제곱법 + __int128로 모듈러 곱셈 처리 |
| 음수 d | 확장 유클리드 결과가 음수일 수 있음 | (x % phi + phi) % phi로 0 이상으로 정규화 |
| N이 작은 경우 | 소인수분해 범위 축소 | i * i <= N 조건으로 불필요한 탐색 방지 |
마무리
이 문제는 RSA 복호 과정을 그대로 구현하는, 정수론과 암호 이론의 기본기를 확인하는 문제입니다. 소인수분해, 오일러 피 함수, 확장 유클리드 알고리즘, 모듈러 거듭제곱이라는 네 가지 핵심 도구만 정확하게 구현하면, 구현량은 많지 않지만 수학적 흐름을 한 번에 복습하기에 좋은 연습 문제입니다.
![Featured image of post [Algorithm] C++ 백준 13618번: RSA](/post/algorithm/2025-12-12-boj-13618-rsa-cpp-solution/wordcloud_hu_7a2926abb2d8dbb7.png)
![[Algorithm] C++ 백준 14449번: Balanced Photo](/post/algorithm/2025-12-15-boj-14449-balanced-photo-cpp-solution/wordcloud_hu_c3927a1977c9e917.png)
![[Algorithm] C++ 백준 27046번: Beauty Contest](/post/algorithm/2025-12-15-boj-27046-beauty-contest-cpp-solution/wordcloud_hu_36b430743b631c29.png)
![[Algorithm] C++ 백준 13618번: RSA](/post/algorithm/2025-12-12-boj-13618-rsa-cpp-solution/wordcloud_hu_ef9169c0740863be.png)
![[Algorithm] C++ 백준 30853번: Black Box](/post/algorithm/2025-12-12-boj-30853-black-box-cpp-solution/wordcloud_hu_87d0c2f42c088d65.png)
![[Algorithm] C++ 백준 31222번 : 수열과 어렵지 않은 쿼리](/post/algorithm/2025-12-12-boj-31222-sequence-and-not-so-hard-queries-cpp-solution/wordcloud_hu_6068bcd736ddbb4b.png)
![[Algorithm] C++ 백준 2709번: 가장 작은 K](/post/algorithm/2025-12-08-boj-2709-smallest-k-last-digits-1-2-cpp-solution/wordcloud_hu_2c72a969698601f4.png)
![[Algorithm] C++/Python 백준 10854번: Divisions - 약수 개수](/post/algorithm/2025-09-16-boj-10854-divisions-number-of-divisors-cpp-python-solution/wordcloud_hu_f2a53254f2f126b2.png)
![[Algorithm] C++ 백준 23575번: Squid Game](/post/algorithm/2025-12-04-boj-23575-squid-game-cpp-solution/wordcloud_hu_3623649df8b22837.png)
![[Algorithm] C++/Python 백준 13926 gcd(n, k) = 1 — φ(n) 계산](/post/algorithm/2025-10-14-boj-13926-gcd-n-k-equals-1-cpp-python-solution/wordcloud_hu_4f80697d0be61606.png)
![[Algorithm] C++ 백준 12728번: n제곱 계산](/post/algorithm/2025-09-16-boj-12728-n-power-calculation-last-three-digits-cpp-solution/wordcloud_hu_767610d37d930d0a.png)