Workspace IndexMath › Day 45

Group Theory Basics (Cyclic Groups, Discrete Log) TODO

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

Concept

A group is a set with a binary operation satisfying associativity, an identity element, and inverses; if the powers of a single element g generate the whole group, it's called cyclic, and g is called a generator. In a finite group, the order of an element is the size of the cyclic subgroup it generates, and by Lagrange's theorem, the size of any subgroup always divides the size of the whole group. The discrete logarithm problem asks: given g and h = g^x in a cyclic group, find the exponent x. Computing the exponent (exponentiation) is fast via repeated squaring, while going the other direction is believed to be hard in a well-chosen group — this asymmetry is the foundation of public-key cryptography. However, hardness depends entirely on the choice of group: if the order of a multiplicative group factors into only small primes, Pohlig-Hellman breaks the problem into smaller pieces, so the group's order needs to be a large prime. Elliptic curve groups are widely used in practice because they offer shorter element representations at the same security level.

When handling signatures or commitments, scalars need to be reduced modulo the group's order — without understanding this structure, it's easy to end up accepting out-of-range scalars or small-subgroup points without checking them, which creates a real vulnerability.

Code & Formula

# 군론 기초(순환군·이산로그) — Z_p^*의 생성원 찾기, 위수(Lagrange), 이산로그 브루트포스
# 교육용 예시: 실제 암호에는 훨씬 큰 소수를 쓴다.

p = 23  # 소수 => Z_p^* = {1,...,p-1}는 위수 p-1 = 22인 순환군

def order_of(g, p):
    """g의 위수: g^k = 1이 되는 최소 양의 k."""
    k, x = 1, g % p
    while x != 1:
        x = (x * g) % p
        k += 1
    return k

group_order = p - 1
print(f"|Z_{p}^*| = {group_order}")

# 모든 원소의 위수를 나열하고 Lagrange 정리(위수는 항상 군의 크기를 나눔) 확인
orders = {g: order_of(g, p) for g in range(1, p)}
for g, o in orders.items():
    assert group_order % o == 0, "Lagrange 정리 위반!"
print("각 원소의 위수(Lagrange 정리: 모두 22를 나눔):")
print({g: o for g, o in list(orders.items())[:6]}, "...")

# 위수가 group_order와 같은 원소 = 생성원(primitive root)
generators = [g for g, o in orders.items() if o == group_order]
print(f"\n생성원들: {generators}")

g = generators[0]
x_secret = 15  # 비밀 지수
h = pow(g, x_secret, p)
print(f"\ng={g}, h=g^x mod p={h} (x는 비밀)")

# 이산로그 브루트포스: h = g^x가 되는 x를 처음부터 찾아본다 (작은 군이라 가능)
for x in range(group_order):
    if pow(g, x, p) == h:
        print(f"브루트포스로 복원한 이산로그 x={x} (정답과 일치: {x == x_secret})")
        break
print("-> 군이 커지면(p가 수백 비트) 이 브루트포스는 우주 나이보다 오래 걸린다 — 이 비대칭성이 공개키 암호의 토대.")

Exercise

For a small prime p, find a generator of the multiplicative group, list the order of every element, and confirm Lagrange's theorem; then brute-force the discrete log in the same group to get a feel for how the difficulty scales with size.

Practical Connection

The secp256k1 curve used by Ethereum signatures is a cyclic group of prime order, and failing to reduce the signature scalar modulo that order leads to real incidents such as signature malleability or key leakage through nonce issues.

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 45 / 52 · 12월 — 암호학·정보이론 (Day 44–52)

개념

군은 결합법칙, 항등원, 역원을 갖춘 이항 연산이 있는 집합이고, 하나의 원소 g의 거듭제곱만으로 전체가 생성되면 순환군이라 하며 g를 생성원이라 부른다. 유한군에서 원소의 위수는 그 원소가 만드는 순환 부분군의 크기이고, Lagrange 정리에 의해 부분군의 크기는 항상 전체 군의 크기를 나눈다. 이산로그 문제는 순환군에서 g와 h = g^x가 주어졌을 때 지수 x를 찾는 문제로, 지수 계산은 반복 제곱으로 빠른 반면 역방향은 적절히 고른 군에서 어렵다고 믿어지는 비대칭성이 공개키 암호의 토대다. 다만 어려움은 군의 선택에 달려 있어, 곱셈군의 크기가 작은 소인수만으로 분해되면 Pohlig-Hellman으로 문제가 잘게 쪼개지므로 군의 위수가 큰 소수여야 한다. 타원곡선 군은 같은 보안 수준에서 원소 표현이 짧아 실무에서 널리 쓰인다.

서명이나 커밋먼트를 다룰 때 스칼라를 군의 위수로 모듈러 연산해야 하는데, 이 구조를 모르면 위수 초과 스칼라나 소부분군(small subgroup) 점을 검사 없이 받아들이는 취약점을 만든다.

코드 · 수식

# 군론 기초(순환군·이산로그) — Z_p^*의 생성원 찾기, 위수(Lagrange), 이산로그 브루트포스
# 교육용 예시: 실제 암호에는 훨씬 큰 소수를 쓴다.

p = 23  # 소수 => Z_p^* = {1,...,p-1}는 위수 p-1 = 22인 순환군

def order_of(g, p):
    """g의 위수: g^k = 1이 되는 최소 양의 k."""
    k, x = 1, g % p
    while x != 1:
        x = (x * g) % p
        k += 1
    return k

group_order = p - 1
print(f"|Z_{p}^*| = {group_order}")

# 모든 원소의 위수를 나열하고 Lagrange 정리(위수는 항상 군의 크기를 나눔) 확인
orders = {g: order_of(g, p) for g in range(1, p)}
for g, o in orders.items():
    assert group_order % o == 0, "Lagrange 정리 위반!"
print("각 원소의 위수(Lagrange 정리: 모두 22를 나눔):")
print({g: o for g, o in list(orders.items())[:6]}, "...")

# 위수가 group_order와 같은 원소 = 생성원(primitive root)
generators = [g for g, o in orders.items() if o == group_order]
print(f"\n생성원들: {generators}")

g = generators[0]
x_secret = 15  # 비밀 지수
h = pow(g, x_secret, p)
print(f"\ng={g}, h=g^x mod p={h} (x는 비밀)")

# 이산로그 브루트포스: h = g^x가 되는 x를 처음부터 찾아본다 (작은 군이라 가능)
for x in range(group_order):
    if pow(g, x, p) == h:
        print(f"브루트포스로 복원한 이산로그 x={x} (정답과 일치: {x == x_secret})")
        break
print("-> 군이 커지면(p가 수백 비트) 이 브루트포스는 우주 나이보다 오래 걸린다 — 이 비대칭성이 공개키 암호의 토대.")

연습

작은 소수 p에 대해 곱셈군의 생성원을 찾아 모든 원소의 위수를 나열하고 Lagrange 정리를 확인한 뒤, 같은 군에서 이산로그를 브루트포스로 풀어 크기 의존성을 체감해 볼 것.

실무 · Verex 연결

이더리움 서명이 쓰는 secp256k1은 소수 위수의 순환군이며, 서명 스칼라를 그 위수로 정규화하지 않으면 서명 malleability나 nonce 관련 키 유출 같은 실제 사고로 이어진다.

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

← 44. 정수론·모듈러 산술46. ECC·디지털 서명 →