Processing math: 100%

수학

2. Shanks' Algorithm

thisisuserr 2024. 8. 22. 22:59

이산 로그 문제(Discrete Logarithm Problem, DLP)

어떠한 원시근 gy에 대해, ygk(modp)를 만족하는 최소의 자연수 k를 찾는 문제이다.

아직까지 해결하기 어려운 문제로 남아 암호학 등에 주로 사용된다.

 

대충 간략하게 브루트포스 알고리즘으로 구성하면, 다음과 같다.

def discreteLog(y, g, mod):
  cur = 1
  cnt = 0
  while True:
    cur = (cur * g) % mod
    cnt += 1
    if cur == y:
      return cnt

print(discreteLog(3, 2, 11))

 

당연하지만 mod가 더럽게 커지면, 사실상 못 쓰는 코드다.

 

Shanks' Algorithm

sqrt decomposition의 핵심 아이디어는 구간을 제곱근 길이의 제곱근 개수로 쪼개서 산술기하 최소 구하는 것처럼 만드는 것이였다.

딱히 연관성은 없지만, 제곱근으로 분할하는 아이디어를 생각해 보자.

 

어떠한 수 p에 대하여, p 미만의 임의의 음이 아닌 정수 x에 대해

0a,bp이고 ap+b을 만족하는 음이 아닌 정수 a,b가 존재한다.

 

먼저 S={1,g,g2,g3,...,gp를 생각하자.

만약 n×gkp(modp)가 어떤 집합 S에 존재한다면,

다음을 만족하는 0k,cpk,c가 존재한다.

 

gcn×gkp(modp)

이제 양변에 gkp을 곱하면, 이산 로그 x=kp+c를 얻는다.

 

만약 해당 알고리즘으로 찾을 수 없다고 하면,

0k<p인 모든 k에 대해 gkn이 성립하지 않는다는 뜻이다.

그러나 원시근의 성질에 의해 이 모든 값들은 다 합동이 아니기 때문에, 모순이 발생한다.

 

시간 복잡도를 분석해 보면, 저 gkp p개를 계산하는 데 시간복잡도는 O(logp)이다.

총 배열 p개, 길이 p의 배열에서 존재 여부 판별시간 O(logp)

따라서 총 O(plogp)의 시간으로 구할 수 있게 된다.

 

아래는 다음 내용을 C++으로 구현한 것이다.

#include <iostream>
#include <set>
#include <cmath>

using namespace std;
typedef long long int LL;

LL mod;

LL pow(LL base, LL exp)
{
  if(exp == 0) return 1;
  if(exp == 1) return base;
  if(exp % 2 == 1) return pow(base, exp - 1) * base % mod;

  LL half = pow(base, exp / 2);
  return half * half % mod;
}

/* base ^ res = target (mod p) */
LL discreteLog(LL base, LL target)
{
  set<LL> s;
  LL sqrtP = ceil(sqrt(mod));
  LL inv_sqrtP = pow(pow(base, sqrtP), mod - 2); //FlT

  //Baby Step, 0 ~ sqrtP
  LL tmp = 1;
  for(LL i = 0; i < sqrtP; i++)
    {
      s.insert(tmp);
      tmp = (tmp * base) % mod;
    }

  //Giant Step
  tmp = 1;
  for(LL i = 0; i < sqrtP; i++)
    {
      LL cur = target * tmp % mod;
      if(s.find(cur) != s.end()) //이산로그 존재
      {
        tmp = 1;
        for(LL j = 0; j < sqrtP; j++)
          {
            if(tmp == cur) return i * sqrtP + j;
            tmp = (tmp * base) % mod;
          }
      }
      tmp = (tmp * inv_sqrtP) % mod;
    }
  return -1; //error
}

'수학' 카테고리의 다른 글

1. 위수와 원시근  (0) 2024.08.13