Sejong University/Number theory

Modular Exponentiation

reindeer002 2022. 4. 23. 01:00
728x90
#역원을 구하기 위한 알고리즘
def extended_gcd(a, b):
    #초기 설정을 위한 초기화
    r1, r2 = a, b
    s1, s2 = 1, 0
    t1, t2 = 0, 1
    
    while(r2 > 0):
        q = r1 // r2
        r = r1 - q * r2 #q는 r2로 r1을 나눈 몫, r은 그 나머지
        r1, r2 = r2, r #r1은 r2로, r2는 r로 초기화
 
        s = s1 - q * s2 #q는 s2로 s1을 나눈 몫, s는 그 나머지
        s1, s2 = s2, s #s1은 s2로 s2는 s로 초기화
 
        t = t1 - q * t2 #q는 t2로 t1을 나눈 몫, t은 그 나머지
        t1, t2 = t2, t #t1은 t2로 t2는 t로 초기화

    return s1 #a*y1 = 1 mod b이므로 s1을 반환
    #s1이 a의 역원이 됨

def crt(p, q, a, b): # x = a mod p, x = b mod q
    m1 = q #m1 = p*q/p
    m2 = p #m2 = p*q/q
    y1 = extended_gcd(m1, p) #m1*y1 = 1 mod p에서 y1은 m1의 역원
    y2 = extended_gcd(m2, q) #m2*y1 = 1 mod q에서 y2는 m2의 역원
    x = y1*a*m1 + y2*b*m2 #x의 값을 구함
    while x <= 0: #x가 음수라면
        x += m1 * m2 #modulo연산 수행(mod m1*m2)
    return x #x반환

def mod_exp(a, e, n):  #a^e mod n
    x = change_bin(e) #e를 이진수로 표현
    s = 1
    for i in range(0, len(x)):
        if x[i] == '1': #x[i]이 1이라면
            r = s*a % n #multply함
        else: #x[i]이 0이라면
            r = s #그대로 초기화
        s = r*r % n #square함
    return r

#e값을 이진수로 변환하여 출력
def change_bin(e):
    binary = ""
    while e >= 1:
        data = e % 2 #나머지
        e = e // 2 #몫
        if data == 1: #나머지가 1이라면
            binary += '1' #이진수 1로 초기화
        else: #나머지가 0이라면
            binary += '0' #이진수 0으로 초기화
    #영상에서 나온 알고리즘을 적용하기 위해 이진수데이터를 반대로 나열
    binary = binary[::-1]
    return binary

print(mod_exp(3, 12345, 97))
print(mod_exp(5, 123456789012345, 976))
print(mod_exp(7, 1234567890123456789, 12345))
print(crt(10, 21, 1, 2))
print(crt(257, 293, 11, 13))
print(crt(123, 457, 1, 34))
728x90