Workspace IndexAlgorithms › Day 88

Multi-Precision Arithmetic (Bignum) — Montgomery and Barrett Reduction (TAOCP Vol. 2), the Real Bottleneck in EC/ZK Implementations TODO

Algorithms · Day 88 / 100 · F. Cryptography & ZK (Day 82-96)

Concept

Multi-precision arithmetic represents integers larger than a machine word as an array of words and operates on them; in cryptographic implementations, the most expensive operation is modular multiplication. Division is far slower than multiplication, so avoiding actual division in modular reduction is the key optimization. Montgomery reduction picks a power of two R coprime with the modulus, moves numbers into Montgomery representation, and then performs reduction using only multiplications and shifts to effectively multiply by R's inverse. Because the representation conversion itself has a cost, it pays off when you do many multiplications under the same modulus in a row, as in modular exponentiation. Barrett reduction precomputes an approximation of the modulus's reciprocal and replaces division with multiplication and shifts; it has no representation conversion, so it suits one-off reductions. Either way, timing differences from conditional branches can leak secret values, so constant-time implementations are required.

A large share of the time spent verifying an elliptic-curve signature or generating a ZK proof goes into field multiplication, so the representation and reduction choice at this layer directly decides throughput and gas cost.

Code & Formula

# 다중정밀 산술(bignum) — Barrett 리덕션을 직접 구현해 나눗셈 없이 모듈러 축약을 하고,
# 파이썬 내장 % 연산과 결과가 일치하는지 검증한다 (Montgomery와 대비되는 단발성 리덕션 기법).

def barrett_precompute(modulus, k):
    """mu = floor(4^k / modulus) 를 미리 계산 — 이후 리덕션에서 나눗셈 대신 시프트+곱셈만 쓴다."""
    return (1 << (2 * k)) // modulus

def barrett_reduce(x, modulus, k, mu):
    """x < modulus^2 가정. 나눗셈 없이 근사 몫을 구하고 보정한다."""
    q_hat = (x * mu) >> (2 * k)
    r = x - q_hat * modulus
    while r >= modulus:      # 근사 오차 보정 (최대 2번이면 충분함이 알려져 있다)
        r -= modulus
    while r < 0:
        r += modulus
    return r

MODULUS = (1 << 61) - 1   # 토이 소수 모듈러스 (61비트)
K = MODULUS.bit_length()
MU = barrett_precompute(MODULUS, K)

import random
random.seed(7)
mismatches = 0
for _ in range(2000):
    a = random.getrandbits(60)
    b = random.getrandbits(60)
    product = a * b                      # 모듈러 곱셈에서 실제로 리덕션이 필요한 값
    expected = product % MODULUS         # 파이썬 내장 나눗셈 기반 리덕션
    got = barrett_reduce(product, MODULUS, K, MU)
    if got != expected:
        mismatches += 1

print("modulus:", MODULUS, "| k (bit length):", K)
print("precomputed mu = floor(4^k / modulus):", MU)
print("random trials:", 2000, "| mismatches vs builtin %:", mismatches)
print("Barrett reduction matches builtin modulo:", mismatches == 0)
print("note: Montgomery reduction instead converts to a special representation")
print("      once and amortizes it over many multiplications (e.g. modexp loops).")

Exercise

Implement modular multiplication over a prime modulus using 64-bit word arrays, once with naive division and once with Montgomery reduction, then compare their runtime performing the same modular exponentiation.

Practical Connection

This layer's cost structure is exactly why Ethereum's pairing and modular-exponentiation precompiles exist, why they're priced the way they are, and where an off-chain proof generator's bottleneck actually sits.

If you study this on a given day, add a note link and a ✅ to this line in the source curriculum (docs/knowledge/dev-100-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/.


한국어

다중정밀 산술(bignum) TODO

Algorithms · Day 88 / 100 · F. 암호학·ZK (Day 82–96)

Montgomery·Barrett 리덕션 (TAOCP 2권), EC·ZK 구현의 실제 병목

개념

다중정밀 산술은 기계어 워드보다 큰 정수를 워드 배열로 표현해 연산하는 기법이며, 암호 구현에서 가장 비싼 연산은 모듈러 곱셈이다. 나눗셈은 곱셈보다 훨씬 느리므로 모듈러 리덕션에서 실제 나눗셈을 피하는 것이 핵심 최적화다. Montgomery 리덕션은 모듈러스와 서로소인 2의 거듭제곱 R을 잡아 수를 Montgomery 표현으로 옮긴 뒤, 곱셈과 시프트만으로 R의 역원을 곱한 결과를 얻어 리덕션을 수행한다. 표현 변환에 비용이 들기 때문에 지수승처럼 같은 모듈러스에서 곱셈을 연달아 할 때 유리하다. Barrett 리덕션은 모듈러스의 역수 근사값을 미리 계산해 두고 나눗셈을 곱셈과 시프트로 대체하며, 표현 변환이 없어 단발성 리덕션에 적합하다. 어느 쪽이든 조건 분기로 인한 실행 시간 차이가 비밀값을 흘릴 수 있으므로 상수 시간 구현이 요구된다.

타원곡선 서명 검증이나 ZK 증명 생성 시간의 상당 부분이 필드 곱셈에 들어가므로, 이 계층의 표현과 리덕션 선택이 곧 처리량과 가스 비용을 결정한다.

코드 · 수식

# 다중정밀 산술(bignum) — Barrett 리덕션을 직접 구현해 나눗셈 없이 모듈러 축약을 하고,
# 파이썬 내장 % 연산과 결과가 일치하는지 검증한다 (Montgomery와 대비되는 단발성 리덕션 기법).

def barrett_precompute(modulus, k):
    """mu = floor(4^k / modulus) 를 미리 계산 — 이후 리덕션에서 나눗셈 대신 시프트+곱셈만 쓴다."""
    return (1 << (2 * k)) // modulus

def barrett_reduce(x, modulus, k, mu):
    """x < modulus^2 가정. 나눗셈 없이 근사 몫을 구하고 보정한다."""
    q_hat = (x * mu) >> (2 * k)
    r = x - q_hat * modulus
    while r >= modulus:      # 근사 오차 보정 (최대 2번이면 충분함이 알려져 있다)
        r -= modulus
    while r < 0:
        r += modulus
    return r

MODULUS = (1 << 61) - 1   # 토이 소수 모듈러스 (61비트)
K = MODULUS.bit_length()
MU = barrett_precompute(MODULUS, K)

import random
random.seed(7)
mismatches = 0
for _ in range(2000):
    a = random.getrandbits(60)
    b = random.getrandbits(60)
    product = a * b                      # 모듈러 곱셈에서 실제로 리덕션이 필요한 값
    expected = product % MODULUS         # 파이썬 내장 나눗셈 기반 리덕션
    got = barrett_reduce(product, MODULUS, K, MU)
    if got != expected:
        mismatches += 1

print("modulus:", MODULUS, "| k (bit length):", K)
print("precomputed mu = floor(4^k / modulus):", MU)
print("random trials:", 2000, "| mismatches vs builtin %:", mismatches)
print("Barrett reduction matches builtin modulo:", mismatches == 0)
print("note: Montgomery reduction instead converts to a special representation")
print("      once and amortizes it over many multiplications (e.g. modexp loops).")

연습

64비트 워드 배열로 소수 모듈러스 위의 곱셈을 구현하되 단순 나눗셈 방식과 Montgomery 방식을 각각 만들고, 같은 모듈러 거듭제곱을 수행해 실행 시간을 비교하라.

실무 · Verex 연결

이더리움의 페어링·모듈러 지수승 프리컴파일이 왜 존재하고 왜 그런 가스 비용을 갖는지, 그리고 오프체인 증명 생성기의 병목이 어디인지가 모두 이 계층의 비용 구조에서 나온다.

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

← 87. 커밋먼트89. 고정소수점 산술과 반올림 정책 →