Workspace IndexMath › Day 20

Linear Algebra over the Finite Field GF(p) (December bridge, Thread A) TODO

Math · Day 20 / 52 · September — Linear Algebra (Day 18-26)

Concept

GF(p) is the finite field formed by the residue classes modulo a prime p, in which every nonzero element has a multiplicative inverse. Linear algebra over this field defines concepts like vector spaces, rank, determinant, and inverse matrices exactly as over the reals, and Gaussian elimination works the same way — except division is replaced by modular multiplicative inverses. A decisive difference from real-number computation is that there's no notion of magnitude comparison or rounding error, so partial pivoting for numerical stability is unnecessary — any nonzero element can serve as a pivot. Also, because every operation is exact, rank and solution sets are determined with zero error, and the fact that the characteristic is p produces phenomena that don't exist over the reals, such as adding something to itself p times giving zero. Interpolation — uniquely recovering a polynomial from its values at distinct points — also holds exactly over this field.

Secret sharing, erasure codes, and most ZK proof systems are all described in terms of polynomials and linear algebra over finite fields, so without this computational intuition you end up treating the libraries as a black box.

Code & Formula

# 유한체 GF(p) 위 선형대수 — 페르마 소정리로 모듈러 역원을 구하고,
# 가우스 소거법을 mod p 로 그대로 적용해 Ax=b (mod p) 를 정확히 푼다.

P = 17  # 작은 소수를 법으로 사용


def mod_inv(a: int, p: int = P) -> int:
    return pow(a % p, p - 2, p)  # 페르마 소정리: a^(p-1) ≡ 1  =>  a^(p-2) ≡ a^-1


def gauss_solve_mod_p(A: list, b: list, p: int = P) -> list:
    n = len(A)
    M = [row[:] + [b[i]] for i, row in enumerate(A)]  # 첨가행렬
    for col in range(n):
        pivot_row = next(r for r in range(col, n) if M[r][col] % p != 0)  # 실수와 달리 크기 비교 불필요
        M[col], M[pivot_row] = M[pivot_row], M[col]
        inv = mod_inv(M[col][col], p)
        M[col] = [(x * inv) % p for x in M[col]]  # 피벗을 1로
        for r in range(n):
            if r != col and M[r][col] != 0:
                factor = M[r][col]
                M[r] = [(M[r][k] - factor * M[col][k]) % p for k in range(n + 1)]
    return [row[-1] for row in M]


A = [[2, 3], [5, 1]]
b = [7, 4]

x = gauss_solve_mod_p(A, b)
print(f"GF({P}) 위에서 Ax ≡ b (mod {P}) 풀이: x = {x}")

# 검산: Ax mod p == b
check = [sum(A[i][j] * x[j] for j in range(2)) % P for i in range(2)]
print(f"검산 Ax mod {P} = {check}, b = {b} → {'일치' if check == b else '불일치'}")

print(f"\n예: 5의 모듈러 역원 mod {P} = {mod_inv(5)}  (검산: 5*inv mod {P} = {5 * mod_inv(5) % P})")

Exercise

Pick a small prime p, implement Gaussian elimination and matrix inversion over GF(p) yourself, and use inverses computed via the extended Euclidean algorithm to check how rank and solution sets differ from the real-number version.

Practical Connection

Shamir secret sharing, Reed-Solomon codes, and polynomial commitments including KZG all stand on polynomial interpolation and linear algebra over finite fields — this is the basic grammar for reading blob data availability and ZK circuits.

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/.


한국어

유한체 GF(p) 위 선형대수 (12월 다리, 스레드 A) TODO

Math · Day 20 / 52 · 9월 — 선형대수 (Day 18–26)

개념

GF(p)는 소수 p에 대한 modulo p 잉여류 집합이 이루는 유한체이며, 0이 아닌 모든 원소가 곱셈에 대한 역원을 가진다. 이 체 위의 선형대수는 벡터공간, 랭크, 행렬식, 역행렬 같은 개념이 실수 위에서와 동일하게 정의되고 가우스 소거법도 그대로 작동하되, 나눗셈이 모듈러 곱셈 역원으로 대체된다. 실수 계산과 결정적으로 다른 점은 크기 비교나 반올림 오차 개념이 없어서, 수치적 안정성을 위한 부분 피벗팅이 필요 없고 0이 아닌 아무 원소나 피벗으로 삼아도 된다는 것이다. 또 모든 연산이 정확하기 때문에 랭크와 해집합이 오차 없이 결정되며, 특성이 p라는 사실 때문에 p번 더하면 0이 되는 등 실수에서는 없는 현상이 나타난다. 서로 다른 점에서의 값으로부터 다항식을 유일하게 복원하는 보간도 이 체 위에서 정확히 성립한다.

비밀 분산, 소거 부호, 그리고 대부분의 ZK 증명계가 유한체 위의 다항식과 선형대수로 서술되므로, 이 계산 감각이 없으면 라이브러리를 블랙박스로만 쓰게 된다.

코드 · 수식

# 유한체 GF(p) 위 선형대수 — 페르마 소정리로 모듈러 역원을 구하고,
# 가우스 소거법을 mod p 로 그대로 적용해 Ax=b (mod p) 를 정확히 푼다.

P = 17  # 작은 소수를 법으로 사용


def mod_inv(a: int, p: int = P) -> int:
    return pow(a % p, p - 2, p)  # 페르마 소정리: a^(p-1) ≡ 1  =>  a^(p-2) ≡ a^-1


def gauss_solve_mod_p(A: list, b: list, p: int = P) -> list:
    n = len(A)
    M = [row[:] + [b[i]] for i, row in enumerate(A)]  # 첨가행렬
    for col in range(n):
        pivot_row = next(r for r in range(col, n) if M[r][col] % p != 0)  # 실수와 달리 크기 비교 불필요
        M[col], M[pivot_row] = M[pivot_row], M[col]
        inv = mod_inv(M[col][col], p)
        M[col] = [(x * inv) % p for x in M[col]]  # 피벗을 1로
        for r in range(n):
            if r != col and M[r][col] != 0:
                factor = M[r][col]
                M[r] = [(M[r][k] - factor * M[col][k]) % p for k in range(n + 1)]
    return [row[-1] for row in M]


A = [[2, 3], [5, 1]]
b = [7, 4]

x = gauss_solve_mod_p(A, b)
print(f"GF({P}) 위에서 Ax ≡ b (mod {P}) 풀이: x = {x}")

# 검산: Ax mod p == b
check = [sum(A[i][j] * x[j] for j in range(2)) % P for i in range(2)]
print(f"검산 Ax mod {P} = {check}, b = {b} → {'일치' if check == b else '불일치'}")

print(f"\n예: 5의 모듈러 역원 mod {P} = {mod_inv(5)}  (검산: 5*inv mod {P} = {5 * mod_inv(5) % P})")

연습

작은 소수 p를 골라 GF(p) 위 행렬의 가우스 소거와 역행렬을 직접 구현하고, 확장 유클리드로 구한 역원을 써서 랭크와 해집합이 실수 버전과 어떻게 다른지 확인하라.

실무 · Verex 연결

Shamir 비밀 분산과 리드-솔로몬 부호, 그리고 KZG를 포함한 다항식 커밋먼트가 모두 유한체 위 다항식 보간과 선형대수 위에 서 있어, 블롭 데이터 가용성과 ZK 회로를 읽을 때의 기본 문법이 된다.

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

← 19. 내적·노름·코사인 유사도21. 리스크·포트폴리오 행렬(공분산·상관) →