↓ 본문으로 건너뛰기

소인수분해 알고리즘(Pollard-(p-1), Pollard-rho, Dixon's Random Square)

·4 분
nyan101
작성자
nyan101
목차

지난번 글에서는 이산 로그 문제에 대해 다뤘으니 이번에는 소인수분해 문제를 해결하는 알고리즘에 대해 알아보자. 코드는 이전과 마찬가지로 아래와 같은 수정이 들어간 파이썬 문법을 따랐다.

  • 양 끝을 명시적으로 나타내기 위해 range(st, ed+1) 대신 [st...ed]와 같은 표기를 사용했다.
  • 파이썬에서 거듭제곱을 나타내는 a**b 대신 일반적으로 사용되는 a^b 표기를 사용했다.

지난 이산 로그 문제와는 달리 모두가 알 것이라 믿고 소인수분해 문제에 대한 자세한 설명은 생략한다. 또한 알고리즘 설계를 간단히 하기 위해 소인수분해 문제의 요구조건을 주어진 자연수 n에 대해, 1과 자기 자신(=n)을 제외한 약수를 발견하는 것으로 정했다.

Brute-Force

가장 간단한 방법은 모든 경우를 계산해보는 것이다. 그런데 $n$이 $a$를 약수로 가지면 $n/a$도 약수로 가진다는 사실을 이용하면 전체 $n$이 아닌 $\sqrt{n}$ 까지만 시도해보면 충분함을 알 수 있다.

def factor(n):
    for d in [2, ..., floor(sqrt(n))]:
        if n % d == 0:
            return d
    return None

이는 $O(\sqrt{n})$ 만큼의 시간이 소요된다. 1억 이하의 작은 수들에 대해서는 충분할 수 있으나, 이보다 큰 숫자들에 대해서는 이후 소개할 알고리즘들을 사용해야 한다.

Pollard-(p-1) Algorithm

Pollard-(p-1) 알고리즘은 페르마 소정리(Fermat’s Little Theorem)을 활용한다. 주어진 $n$이 어떤 소수 $p$를 약수로 가진다면 페르마 소정리에 의해 $a^{p-1} \equiv 1 \pmod p$ 이 성립하고, 이는 자연수 $k$에 대해 $a^{(p-1)\cdot k} - 1$이 $p$의 배수가 됨을 의미한다. 다시 말해, 어떤 자연수 $m$이 $p-1$의 배수가 된다면 $gcd(a^m - 1, n)$ 은 최소한 $p$를 약수로 가지게 된다.

pollard-(p-1) 알고리즘에서는 적당히 큰 $B$에 대해 $(p-1) \| B!$ 이 성립하기를 기대한다. 만일 $p-1$이 $B$보다 큰 소인수를 가지지 않고1, 각 소인수가 포함된 개수2가 크지 않다면 $(p-1) \| B!$ 을 만족할 수 있다. 이를 이용한 코드를 아래에 작성했다. 알고리즘에서 $a$의 선택은 영향을 미치지 않으나 일반적으로 2를 사용한다.

def factor(n, B=1000):
    a = 2
    for i in [1, ..., B]:
        a = (a^i) % n
    d = gcd(a-1, n)
    if 1 < d < n: # d == 1 means B is too low
        return d  # d == n means B is too high
    else:
        return None

역으로 말해, 이러한 알고리즘으로 소인수분해되지 않게 하려면 n의 소인수 p가 (p-1)​이 큰 소인수를 가진다는 조건을 만족하도록 설정해야 한다.

Pollard-rho Algorithm

pollard-rho(ρ) 알고리즘은 지난 이산 로그 문제에서와 마찬가지로 일종의 충돌쌍을 이용해 소인수를 찾는 방식이다. 구체적으로, 어떤 $x, x'$이 $x\neq x'$, $x \equiv x' \pmod p$을 만족한다면 $gcd(x - x', n)$ 은 최소한 $p$를 약수로 가진다는 사실을 이용한다. 랜덤한 $a, b$들을 시험해보면서 $gcd(a - b, n)>1$ 을 만족하는지 알아보는 대신, 조사를 효율적으로 진행하기 위해 변환규칙을 사용한다.

위 알고리즘에서의 변환규칙 $f()$를 보면 한번 충돌($x_{i}=x_{2i}$)이 발생하면 $x_{i+1}=x_{2i+1},\cdots$ 로 계속 이어짐을 쉽게 파악할 수 있다. 따라서 1칸씩 움직이는 $s_i$와 2칸씩 움직이는 $s_{2i}$, 이렇게 2개만을 이용해도 많은 쌍을 동시에 검증하는 효과를 얻을 수 있다.

이전 글에서의 Pollard-rho 알고리즘 설명 중

이산 로그 문제에서와 달리 이번에는 변환규칙 $x_{i+1} = f(x_i)$을 정할 때 경우를 나누지 않으며, 일반적으로 $f(x) = x^2 + 1$을 많이 사용한다.

def factor(n, max_iter=1000):
    # transition rule
    def f(x):
        return (x*x + 1) % n
    # function main
    x1 = x2 = 1
    for i in [0...max_iter]:
        x1 = f(x1)
        x2 = f(f(x2))
        d = gcd(x1 - x2, n)
        if 1 < d < n:
            return d
    return None

Dixon’s Random Square Algorithm

만일 $x^2 \equiv y^2 \pmod n$이고 $x \not \equiv \pm y \pmod n$ 를 만족하는 $x,y$를 찾으면 $gcd(x-y, n) > 1$이 성립하므로 $n$의 약수를 찾을 수 있게 된다. Dixon’s Random Square 알고리즘은 이러한 $x, y$를 찾는 방법을 제시한다.

알고리즘은 다음과 같이 진행된다.

  1. 소수들의 집합 $B = \{p_1, p_2, \cdots, p_t\}$를 정한다. (일반적으로 작은 순으로 $t$개의 소수들을 사용)

  2. 랜덤한 $x_1, x_2, \cdots$들에 대해 다음을 진행한다.

    • $x_i^2 \equiv b_i \pmod n$에 대해 $b_i$를 $B$에 속한 소수들로 인수분해한다. $b_i = \prod_{p_j \in B} p_j^{c_j}$ 꼴로 정리하면 $b_i$를 $\langle c_1, c_2, \cdots, c_t \rangle$ 로 쓸 수 있으며, $B$에 속한 소수들만으로 인수분해가 불가능할 경우 새로운 $x_i$를 뽑는다.
  3. 2번 과정을 거치면서 구한 벡터들 $\langle c_1, c_2, \cdots, c_t \rangle_{\{i\}}$ 을 결합해 모든 원소가 짝수인 벡터(=제곱수)를 만들 수 있는지 확인한다.

    → 해당 벡터를 만드는 $\prod x_i$와 $\sqrt{\prod b_i}$는 각각 $a^2 \equiv b^2 , a \not \equiv \pm b \pmod n$ 를 만족하는 $a, b$가 된다. 만일 $a \equiv \pm b \pmod n$이라면 계속 탐색을 진행한다

실제 예시를 통해 살펴보자. $B = \{2, 3, 5, 7, 11, 13\}$ 을 이용해 $n=15770708441$을 소인수분해하려고 하고, 아래와 같은 정보를 얻었다고 하자.

$$ \begin{align*} (2773700011)^2 & \equiv 2 \times 3\times 13 &\pmod n\\ (8340934156)^2 & \equiv 3 \times 7 &\pmod n\\ (12044942944)^2 & \equiv 2 \times 7 \times 13 & \pmod n \end{align*} $$

이를 종합하면 다음을 얻을 수 있다.

$$ (8340934156 \times 12044942944 \times 2773700011)^2 \equiv (2 \times 3 \times 7 \times 13)^2 \pmod n $$

계산하면 식의 왼쪽은 $(9503435785)^2$, 오른쪽은 $(246)^2$ 이 되고, 여기에 유클리드 알고리즘을 이용해 $(9503435785 - 246)$과 $15770708441$ 의 공약수를 구하면 n의 자명하지 않은 약수 $15770708441$을 얻을 수 있다.

알고리즘의 핵심이 되는 3번 과정은 $\langle c_1, c_2, \cdots, c_t \rangle_{\{i\}}$ 에 $\mathbb{Z}_2$ 위에서의 가우스 소거법을 적용해 찾아낼 수 있다.



  1. 이러한 성질을 B-smooth 라고 한다. ↩︎

  2. $p-1 = \prod q_i^{c_i}$에서 $c_i$ ↩︎

관련 글

이산 로그 문제(DLP)에 대한 알고리즘(Shanks, Pollard-rho, Pohlig-Hellman)

·6 분
암호학, 특히 공개키 기반 암호시스템은 주로 1)소인수분해 문제 혹은 2)이산 로그 문제를 기반으로 설계되는 경우가 많다. 그중 이산 로그 문제와 이를 해결하는 알고리즘에 대해 알아보자. 예시로 든 코드는 기본적으로 파이썬 문법을 따라 작성했으며 가독성을 위해 다음과 같은 부분을 수정했다. 파이썬에서 range(n)은 0부터 시작해 n이 아닌 n-1까지를 포함한다. 양 끝을 명시적으로 나타내기 위해 [st...ed]와 같은 표기를 사용했다. 파이썬에서 거듭제곱을 나타내는 a**b 대신 일반적으로 사용되는 a^b 표기를 사용했다. mod p에서의 역원을 a^(-1)로 표기했다. 실제 구현에서는 다음과 같이 구할 수 있다. 페르마 소정리에 의해 $a^{p-1} \equiv 1 \pmod p$이므로 $a\cdot a^{p-2} \equiv 1$에서 $a^{-1} \equiv a^{p-2}$ $p$가 소수가 아닌 경우, 확장 유클리드 알고리즘을 사용한다 이산 로그 문제 이산 로그 문제는 이산 대수 문제라고도 하며, 순환군 $\langle g \rangle$와 군의 원시근(primitive root) $g$, 그리고 $y \in \langle g \rangle$ 가 주어졌을 때, $y=g^k$를 만족하는 최소의 자연수 $k$를 찾는 문제이다. 암호학에서는 큰 소수 $p$에 대해 $p$로 나눈 나머지들의 모임인 $\mathbb{Z}_p^\ast$를 사용하는 경우가 많다.

Möbius 함수의 정의와 활용

·1 분
얼마 전 코드포스에서 흥미로운 문제를 접했다. 대회 당시에는 풀지 못했는데, 에디토리얼을 읽어보던 중 뫼비우스 함수(Möbius function)에 대한 언급이 있어 이에 대해 좀더 자세히 알아보았다. Möbius function의 정의 뫼비우스 함수(Möbius function)는 자연수 n에 대해 다음과 같이 정의된다. (\(p\)는 소수)

소수 판별 튜링머신

·3 분
이번 SCTF(Samsung CTF)의 700점짜리 문제로 튜링머신 설계가 나왔다. 총 4개의 문제 중 3개는 일반적인 오토마타 교과서에서 다루는 언어들(ex: \(L=\{ 0^n1^n | n \geq 0 \}\))이었지만 마지막 단계인 \(L=\{0^p | p \, \mathrm{\,is\,prime}\}\)가 다소 많은 시간을 잡아먹었다. 사실상 소수 판별을 하는 튜링 머신을 설계하라는 문제였는데, 기억상 다른 교재들에서도 이에 대한 명확한 실례는 나와있지 않아 따로 정리했다. 아래 등장하는 그래프의 화살표에서 A/B . P는 “현재 state에서 알파벳 A를 읽었을 때, 테이프에 B를 쓰고 P방향(L, 또는 R)으로 이동한다"라는 의미를 가진다. 이제 필요한 서브루틴을 하나씩 구성해 보자.