Post-quantum migration is a coordination problem, not a cryptography problem TODO
Concept
Quantum computers break discrete log and integer factorization via Shor's algorithm, which threatens today's elliptic-curve signatures, while Grover's algorithm lowers the search difficulty of hashes but is fairly easily countered by lengthening the output. The replacement algorithms themselves — lattice-based, hash-based, and so on — have already gone through standardization, so what remains hard isn't the math, it's deployment and coordination. Changing a blockchain's signature scheme is a consensus-rule change that needs a hard fork, requiring wallets, hardware signers, bridges, indexers, and audited contracts to move in lockstep, and larger keys and signatures also mean more block space and verification cost. Accounts whose public key is already exposed on-chain, plus the harvest-now-decrypt-later threat — where data collected today is decrypted later — mean the strategy of "migrate after the risk becomes real" doesn't hold, which raises the coordination pressure further. So the practical transition usually goes through a hybrid phase that requires both the old and the new scheme at once, moving gradually from there.
The failure point in a cryptographic transition is never the algorithm choice — it's a design with no migration path — and that has a direct bearing on how you design key management and upgradability in the system you're building right now. This is especially lethal in on-chain systems where keys are permanently pinned.
Code & Formula
# 포스트퀀텀 전환은 조정(coordination) 문제 — 하나의 스킴을 한번에 스왑하는 대신
# 클래식 서명 + 해시 기반(PQ 내성) 서명을 함께 요구하는 "하이브리드 검증" 예시.
# 해시 기반 Lamport 서명은 실제로 양자 내성이 있다고 여겨지는 원시연산이다(1회용).
import hashlib, hmac, os
def H(b: bytes) -> bytes:
return hashlib.sha256(b).digest()
def msg_to_bits(msg: bytes, bits: int) -> list:
n = int.from_bytes(hashlib.sha256(msg).digest(), "big")
return [(n >> i) & 1 for i in range(bits)]
# --- Lamport 서명: 해시만으로 구성된 PQ 내성 1회용 서명 ---
def lamport_keygen(bits=16):
sk = [(os.urandom(16), os.urandom(16)) for _ in range(bits)]
pk = [(H(a), H(b)) for a, b in sk]
return sk, pk
def lamport_sign(msg, sk):
bits = msg_to_bits(msg, len(sk))
return [sk[i][b] for i, b in enumerate(bits)]
def lamport_verify(msg, sig, pk):
bits = msg_to_bits(msg, len(pk))
return all(H(sig[i]) == pk[i][b] for i, b in enumerate(bits))
# --- "클래식" 서명: 지금 널리 쓰이는 스킴(ECDSA 등)의 자리 표시자 (양자에 취약하다고 가정) ---
classical_key = os.urandom(32)
def classical_sign(msg):
return hmac.new(classical_key, msg, hashlib.sha256).digest()
def classical_verify(msg, sig):
return hmac.compare_digest(classical_sign(msg), sig)
# --- 하이브리드 검증: 둘 다 통과해야 유효 — 한쪽이 깨져도 즉시 전면 위험에 빠지지 않는다 ---
def hybrid_verify(msg, classical_sig, pq_sig, pq_pk):
return classical_verify(msg, classical_sig) and lamport_verify(msg, pq_sig, pq_pk)
msg = b"withdraw 100 to addr X"
sk, pk = lamport_keygen()
c_sig = classical_sign(msg)
pq_sig = lamport_sign(msg, sk)
print("정상 트랜잭션 하이브리드 검증:", hybrid_verify(msg, c_sig, pq_sig, pk))
forged_classical = os.urandom(32) # 양자 컴퓨터가 클래식 서명을 위조했다고 가정
print("클래식 서명만 위조돼도 하이브리드는 거부:", not hybrid_verify(msg, forged_classical, pq_sig, pk))
docs/code/algorithms/algorithms-95.py
Exercise
In a system you work on, list every point where the signature algorithm is locked to exactly one choice, and write down what would need to change at each point to allow both algorithms to be accepted at once.
Practical Connection
If Verex's contracts hard-code how signatures are verified, there's no migration path when the scheme needs to change later, so keeping the verifier as a swappable module is what real preparedness looks like.
Where it lands in Jayverse
- Wallet: keep the client-side signing path pluggable too. Not just Verex's contracts — the embedded wallet's signing logic should accept a swappable curve/scheme, so a future hybrid PQ transition doesn't force a full wallet rewrite.
- Bridge: put a scheme-version field in the message format now. Add a signature-scheme identifier to the relayer's cross-chain message format while it only ever holds today's ECDSA value, so a later hybrid transition is a version bump, not a breaking change.
- Personas: route persona signature checks through the same shared verifier. Don't hardcode secp256k1 verification inside the persona token contract; reuse Verex's swappable verifier module so a future migration is one shared upgrade instead of four separate ones.
Key expressions
| Expression | 뜻 · 쓰이는 자리 |
|---|---|
| have a direct bearing on | ~에 직접적인 영향을 미치다 · 한 사실이 다른 설계 판단에 바로 연결될 때. "has a direct bearing on how you design key management" |
| lethal | 치명적인 · 어떤 문제가 특정 상황에서 특히 위험할 때. "especially lethal in on-chain systems" |
| move in lockstep | 보조를 맞춰 함께 움직이다 · 여러 주체가 동시에, 일사불란하게 바뀌어야 할 때. "move in lockstep" |
| coordination pressure | 조정 부담, 조율 압박 · 여러 당사자를 맞춰야 해서 생기는 압박. "raise the coordination pressure further" |
| pinned | 영구히 고정된 · 한 번 정해지면 바꾸기 힘든 상태. "keys are permanently pinned" |
| harvest-now-decrypt-later | 지금 데이터를 모아뒀다가 나중에 해독하는 위협 시나리오 · 미래 기술로 과거 데이터가 뚫릴 위험. "the harvest-now-decrypt-later threat" |
| swappable module | 교체 가능한 모듈 · 나중에 통째로 바꿔 끼울 수 있게 설계된 부품. "keeping the verifier as a swappable module" |
| Shor's algorithm | 쇼어 알고리즘(Shor's algorithm) · 양자컴퓨터로 이산로그·소인수분해를 다항시간에 푸는 알고리즘, 타원곡선 서명을 위협. "break discrete log and integer factorization via Shor's algorithm" |
| Grover's algorithm | 그로버 알고리즘(Grover's algorithm) · 양자 탐색으로 해시 탐색 난이도를 제곱근만큼 낮추는 알고리즘, 출력 길이를 늘려 대응 가능. "Grover's algorithm lowers the search difficulty of hashes" |
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/.