Workspace IndexMath › Day 44

Number Theory and Modular Arithmetic TODO

Math · Day 44 / 52 · December — Cryptography & Information Theory (Day 44-52)

Concept

Modular arithmetic identifies integers by their remainder modulo n; addition, subtraction, and multiplication are all compatible with the remainder operation, but division is only defined when an inverse exists. a has a multiplicative inverse mod n if and only if gcd(a, n) = 1, and that inverse can be obtained via the extended Euclidean algorithm by solving ax + ny = 1. When n is a prime p, every nonzero element has an inverse, making it a finite field; by Fermat's little theorem, a^(p-1) ≡ 1 (mod p), so the inverse can also be computed as a^(p-2). Euler's theorem generalizes this: whenever gcd(a, n) = 1, a^φ(n) ≡ 1 (mod n), which is the basis for how exponents are handled in RSA-type systems. The Chinese Remainder Theorem states that a system of congruences over pairwise coprime moduli has a unique solution modulo their product, and it's used to split large-number arithmetic into computations over smaller moduli.

Elliptic curve operations, hash-to-field, and ZK circuit arithmetic all run over finite fields, so without understanding modular inverses and overflow handling you can't judge either the correctness or the performance of cryptographic code.

Code & Formula

# 정수론·모듈러 산술 — 확장 유클리드로 모듈러 역원 구하기 + 페르마 소정리로 교차검증
# ax + ny = gcd(a, n) 을 풀어 gcd=1이면 x가 곧 a의 (mod n) 역원이다.

def ext_gcd(a, n):
    """확장 유클리드: (g, x, y) with a*x + n*y = g = gcd(a, n)."""
    old_r, r = a, n
    old_x, x = 1, 0
    old_y, y = 0, 1
    while r != 0:
        q = old_r // r
        old_r, r = r, old_r - q * r
        old_x, x = x, old_x - q * x
        old_y, y = y, old_y - q * y
    return old_r, old_x, old_y

def mod_inverse(a, n):
    g, x, _ = ext_gcd(a, n)
    if g != 1:
        raise ValueError(f"{a}는 mod {n}에서 역원이 없음 (gcd={g})")
    return x % n

p = 1_000_000_007  # 큰 소수
for a in (3, 12345, 999_999_999):
    inv = mod_inverse(a, p)
    check = (a * inv) % p
    fermat_inv = pow(a, p - 2, p)  # 페르마 소정리: a^(p-2) ≡ a^-1 (mod p)
    print(f"a={a:>10}  ext_gcd 역원={inv:>10}  a*inv mod p={check}  "
          f"페르마 역원과 일치={inv == fermat_inv}")

# 소수가 아닌 법에서는 gcd(a,n)=1일 때만 역원이 존재함을 확인
n = 20
for a in range(1, n):
    from math import gcd
    if gcd(a, n) == 1:
        print(f"mod {n}: a={a} 역원={mod_inverse(a, n)}")

Exercise

Implement the extended Euclidean algorithm yourself to find the inverse of a modulo an arbitrary prime p, then compute the same value as a^(p-2) mod p and confirm the two results match.

Practical Connection

The reason Solidity fixed-point math uses patterns like mulDiv — multiplying before dividing — and the fact that division over a finite field is really multiplication by an inverse, connect directly to both the precision design of LMSR price calculations and the code that verifies them.

If you study this on a given day, add a note link and a ✅ to this line in the source curriculum (docs/knowledge/math-50-curriculum.md) and this spot will lead straight to the note body. You can also write directly on this page — but regenerating overwrites it, so it's safer to keep anything you want to save as markdown under docs/algorithms/.


한국어

정수론·모듈러 산술 TODO

Math · Day 44 / 52 · 12월 — 암호학·정보이론 (Day 44–52)

개념

모듈러 산술은 정수를 법 n으로 나눈 나머지로 동일시하는 체계로, 덧셈·뺄셈·곱셈은 나머지 연산과 잘 호환되지만 나눗셈은 역원이 존재할 때만 정의된다. a가 법 n에서 곱셈 역원을 가질 필요충분조건은 gcd(a, n) = 1이며, 그 역원은 확장 유클리드 알고리즘으로 ax + ny = 1을 풀어 얻는다. n이 소수 p이면 0이 아닌 모든 원소가 역원을 가져 유한체가 되고, 페르마의 소정리에 의해 a^(p-1) ≡ 1 (mod p)이므로 역원을 a^(p-2)로도 구할 수 있다. 오일러 정리는 이를 일반화해 gcd(a, n) = 1일 때 a^φ(n) ≡ 1 (mod n)을 주며, 이것이 RSA류 시스템에서 지수를 다루는 근거다. 중국인의 나머지 정리는 서로소인 법들에 대한 합동식 체계가 그 곱을 법으로 유일한 해를 가짐을 말해 주고, 큰 수 연산을 작은 법들로 쪼개 계산하는 데 쓰인다.

타원곡선 연산, 해시-투-필드, ZK 회로의 산술이 전부 유한체 위에서 돌아가므로, 모듈러 역원과 오버플로 처리를 이해하지 못하면 암호 코드의 정확성도 성능도 판단할 수 없다.

코드 · 수식

# 정수론·모듈러 산술 — 확장 유클리드로 모듈러 역원 구하기 + 페르마 소정리로 교차검증
# ax + ny = gcd(a, n) 을 풀어 gcd=1이면 x가 곧 a의 (mod n) 역원이다.

def ext_gcd(a, n):
    """확장 유클리드: (g, x, y) with a*x + n*y = g = gcd(a, n)."""
    old_r, r = a, n
    old_x, x = 1, 0
    old_y, y = 0, 1
    while r != 0:
        q = old_r // r
        old_r, r = r, old_r - q * r
        old_x, x = x, old_x - q * x
        old_y, y = y, old_y - q * y
    return old_r, old_x, old_y

def mod_inverse(a, n):
    g, x, _ = ext_gcd(a, n)
    if g != 1:
        raise ValueError(f"{a}는 mod {n}에서 역원이 없음 (gcd={g})")
    return x % n

p = 1_000_000_007  # 큰 소수
for a in (3, 12345, 999_999_999):
    inv = mod_inverse(a, p)
    check = (a * inv) % p
    fermat_inv = pow(a, p - 2, p)  # 페르마 소정리: a^(p-2) ≡ a^-1 (mod p)
    print(f"a={a:>10}  ext_gcd 역원={inv:>10}  a*inv mod p={check}  "
          f"페르마 역원과 일치={inv == fermat_inv}")

# 소수가 아닌 법에서는 gcd(a,n)=1일 때만 역원이 존재함을 확인
n = 20
for a in range(1, n):
    from math import gcd
    if gcd(a, n) == 1:
        print(f"mod {n}: a={a} 역원={mod_inverse(a, n)}")

연습

확장 유클리드 알고리즘을 직접 구현해 임의의 소수 p에 대해 a의 역원을 구하고, 같은 값을 a^(p-2) mod p로도 계산해 두 결과가 일치하는지 확인해 보라.

실무 · Verex 연결

Solidity에서 고정소수점 계산을 할 때 mulDiv 같은 패턴으로 곱셈을 먼저 하고 나누는 이유, 그리고 유한체 위의 나눗셈이 실제로는 역원 곱셈이라는 사실은 LMSR 가격 계산의 정밀도 설계와 검증 코드 양쪽에 직접 연결된다.

공부한 날 원본 커리큘럼(docs/knowledge/math-50-curriculum.md)의 이 줄에 노트 링크와 ✅ 를 붙이면, 이 자리는 노트 본문으로 바로 이어집니다. 노트 없이 이 페이지에 바로 적어도 됩니다 — 다만 다시 생성하면 덮어쓰이므로, 남길 글은 docs/algorithms/ 의 마크다운으로 쓰는 편이 안전합니다.

← 43. 상관관계와 공적분(가볍게)45. 군론 기초(순환군·이산로그) →