ZK and TEE? Why? (Based on blockchain)
블록체인 보안을 완성하는 수학과 하드웨어의 결합
1. 들어가며
블록체인은 “누구도 믿지 않는다(trustless)”는 개념으로 시작했지만, 모든 연산이 공개되어야 한다는 역설을 안고 있다. 이 투명성은 사용자들에게 신뢰를 줄 수 있지만, 동시에 프라이버시 침해를 초래한다.
문제점을 정리하면 아래와 같다.
- 모든 노드가 모든 연산을 반복해야 하고 (비효율),
- 모든 데이터가 모두에게 공개된다. (프라이버시)
이를 해결하기 위해 등장한 기술이 영지식 증명(Zero-Knowledge Proof, ZKP) 이다. ZKP는 “계산이 올바르게 수행되었음”을 증명하면서, 그 계산의 입력값은 완전히 숨길 수 있다.
그러나 ZKP에도 한계가 있다. “비밀 데이터가 실제로 진짜인지”를 보장하지는 못한다. 즉, 거짓된 입력을 회로에 넣고 올바른 증명을 만들어내는 시도를 막을 방법이 없다.
이 공백을 메우기 위해 TEE(Trusted Execution Environment)를 사용할 수 있다. TEE는 하드웨어 레벨에서 비밀 데이터를 보호하고, 그 데이터가 정상 하드웨어에서 발생했음을 attestation(보증) 으로 입증한다.
Part 1. 영지식 증명(ZKP)의 수학적 원리
2. 증명(Proof)의 본질
ZKP를 이해하기 위해선 먼저 “증명(Proof)”이 뭔지 알아보자
- 어떤 명제(statement)가 참임을 입증하기 위해,
- 증명자(Prover)는 비밀 데이터(witness) 를 사용해 수학적 제약식을 만족함을 보여준다.
- 검증자(Verifier)는 비밀을 보지 않고도 그 명제가 참임을 확신한다.
이때, 모든 연산은 다항식 제약식(polynomial constraints) 형태로 표현된다:
[ f(x, w) = 0 ]
여기서:
- ( x ): 공개 입력 (public input)
- ( w ): 비공개 입력 (private witness)
즉, “공개된 x와 함께 f(x, w)=0을 만족하는 비밀 w를 알고 있다.”(근데 비밀은 알려주지 않고 증명) 이것이 영지식 증명이 증명하는 수학적 구조다.
3. Public Input과 Private Input의 관계
위에서 말했듯, ZK 회로에서 입력값은 두 종류로 나뉜다:
| 구분 | 역할 | 예시 |
|---|---|---|
| Public Input (x) | 모두가 아는 값, 검증자&증명자가 보는 값 | root, dst, amount, nullifier |
| Private Input (w) | 증명자만 아는 값, 숨기고 싶은 데이터 | balance, sk, nonce, merkle_path |
이 둘은 회로의 제약식(polynomial constraints)으로 연결된다.
예를 들어 “내 잔고(balance)가 송금 금액(amount)보다 크고, 머클루트(root)에 포함되어 있다”는 것을 증명하려면:
balance ≥ amount
MerklePath(balance, sk, nonce) == root
즉, 공개 데이터(root, amount)가 비밀 데이터(balance, sk, nonce, merkle_path)의 함수로 결정되며 (주의: 단순 예시임),
ZK proof는 그 관계가 성립함을 보장한다.
검증자는 balance의 값을 몰라도,
“그런 balance가 존재한다”는 사실을 암호학적으로 확신할 수 있다.
이 확신은 P와 NP를 통해 이해할 수 있다.
4. 계산의 복잡도 — P와 NP
영지식 증명은 P vs NP 문제의 본질 위에 서 있다.
P: 해답을 빠르게 찾을 수 있는 문제
NP: 해답을 빠르게 검증할 수 있는 문제
이게 무슨 말인지 모르겠다면, 스도쿠 문제를 생각해보자.
P: 스도쿠 문제가 풀렸음을 빠르게 훑어볼 수 있음
NP: 스도쿠 문제를 풀기 위해 하루종일 붙잡고 있음
ZK 시스템에서는
- 검증자(Verifier)는 제공된 증명으로 해가 맞는지 검증 (P-time)
- 증명자(Prover)는 실제 계산을 수행하고 해를 찾는 역할 (NP-hard)
로 P와 NP 문제의 특성을 사용한다.
즉, ZK는 “NP 문제를 효율적으로 검증하는 방법” 이다.
모든 노드가 복잡한 계산을 직접 하지 않아도, 하나의 짧은 proof만으로 연산의 정당성을 빠르게(P-time) 확인할 수 있게 된다.
이것이 ZK Rollup, zkBridge 같은 시스템의 수학적 근본이다.
5. 영지식(Zero-Knowledge) 속성
ZKP는 세 가지 보안 속성을 가진다:
| 속성 | 설명 |
|---|---|
| Completeness (완전성) | 정직한 증명자는 검증자에게 항상 통과되는 proof를 만들 수 있음 |
| Soundness (정당성) | 거짓된 명제를 참으로 속일 수 있는 확률은 거의 0 |
| Zero-Knowledge (영지식성) | proof를 통해 비밀 데이터에 대한 정보는 아무것도 누출되지 않음 |
예시를 들어보자면,
완전성 - 비밀을 알고있는 내가 정상 증명을 제출하면, 검증에 실패해서는 안된다. 정당성 - 가짜 증명을 제출하면, 검증에 실패할 확률이 거의 1이어야 한다. 영지식성 - 내가 숨기고자 한 비밀은 증명 생성 시에 누출되어서는 안된다.
Part 2. 블록체인에서의 ZKP 아키텍처
6. 머클트리와 상태 커밋
위에서 예시를 든 ‘잔고’ 데이터를 가리기 위해, 상상을 통해 영지식 증명 시뮬레이션을 돌려보자.
이더리움에서 계정/컨트랙트의 잔고 등 실제 state는 Keccak 기반 Merkle Patricia Trie(MPT)로 구성되어 있다. 궁금하면 공식 docs를 읽어보자.
하지만 Keccak을 사용한 해시는 영지식 회로 내에서 비효율적이다. 그래서 ZK-friendly 해시(Poseidon, Rescue 등)를 사용한 별도의 상태 트리를 구성한다 (실제 state 트리와 동기화되었다고, 또는 ERC20 token이라고 가정해보자).
예시 구조:
leaf = Poseidon(pk_hash, balance, nonce)
root = Merkle(leaf[])
root는 컨트랙트의 상태 커밋으로 저장되고,
ZK proof는 “내 leaf가 이 root에 포함된다”는 것을 증명한다.
7. Trusted Setup과 Proof 생성
zk-SNARK은 “Trusted Setup”을 필요로 한다. 이는 특정 회로에 대해 생성된 공통 참조 문자열(CRS) 로, 이 안에는 절대 유출되어선 안 되는 “toxic waste” (랜덤 시드)가 존재한다.
- 만약 이 값이 노출되면 누구나 “가짜 증명”을 만들어낼 수 있다.
- 따라서 MPC Ceremony(여러 객체가 각 부분을 생성) 으로 안전하게 생성하고, 모든 중간 데이터를 영구 폐기해야 한다!
- 이후 “universal setup” 혹은 “transparent proof system”(PLONK, STARK)으로 발전하면서 setup 의존성을 제거하기도 한다.
8. 위 예시에서의 간단한 Proof 흐름
- 사용자(증명자)는 TEE(추후 설명) 내부에서 비밀값(
balance,sk,nonce)을 로드 - 회로(
balance ≥ amount,MerklePath(leaf)==root) 만족 여부를 검증 - 증명 생성 (Groth16, PLONK 등)
- proof + public inputs(root, amount, nullifier 등)를 온체인 컨트랙트에 제출
- 검증 컨트랙트가 Verifier 키로 proof 검증 → 성공하면 상태 갱신
즉, 블록체인 전체의 계산을 “ZK proof + 상태 루트(root) 갱신” 로 압축하는 셈이라고 이해할 수 있다.
Part 3. TEE(Trusted Execution Environment) — 하드웨어 신뢰의 역할
9. TEE란 무엇인가
TEE(Trusted Execution Environment) 는 CPU 내부의 격리된 보안 영역으로, 운영체제나 하이퍼바이저가 접근할 수 없는 메모리 공간에서 코드를 실행한다.
대표적인 예시로는 아래의 것들이 존재한다.
- Intel SGX – 서버/클라우드용 enclave, 블록체인 대부분이 해당 환경을 사용할 것이다.
- ARM TrustZone – 모바일/임베디드용 secure world, 수십 MB로 가볍고 작은 경우 사용할 수 있다.
- AMD SEV, Apple SEP 등 유사 구조 존재
TEE 내부에서 보통 하는 역할은 다음과 같다.
- 외부(OS, Hypervisor 등)에서 접근 불가능한 메모리 공간에서
- 하드웨어로 검증된 코드만 실행되며
- 결과는 attestation 서명 으로 “정상 실행됨”을 외부에 증명할 수 있다.
10. 왜 TEE가 필요한가 — ZKP의 빈틈을 메우다
ZKP는 계산의 “정당성(correctness)” 은 증명하지만, 입력 데이터의 “진실성(authenticity)” 은 보장하지 않는다.
즉, 아래 두 문제를 스스로는 해결할 수 없다.
-
입력이 실제 존재하는 데이터인가? (예: balance를 임의로 조작해도 회로만 맞으면 증명 생성 가능)
-
입력이 노출되면 어떻게 되는가? (private input 유출 → 프라이버시 붕괴)
TEE를 사용하면 위 문제를 하드웨어 레벨에서 해결하기를 기대(..)할 수 있다.
| 문제 | TEE로 해결 가능 |
|---|---|
| 입력의 진위성 | attestation 서명으로 보장 |
| 입력의 기밀성 | secure memory 격리 |
| Prover 조작 방지 | 코드 무결성 attestation |
| 외부 접근 방지 | OS/Hypervisor 접근 차단 |
11. TEE + ZKP 구조
┌────────────────────────────┐
│ Blockchain │
│ ──────────────────────── │
│ SmartContract (Verifier) │
│ ├ verify(proof, quote) │
│ └ updateRoot() │
└────────────────────────────┘
⬆
┌────────────────────────────┐
│ ZK Prover (offchain) │
│ ──────────────────────── │
│ Receives: TEE attestation │
│ Generates: zkProof │
└────────────────────────────┘
⬆
┌────────────────────────────┐
│ TEE (e.g. SGX) │
│ ──────────────────────── │
│ Reads: balance, sk │
│ Computes: Poseidon(leaf) │
│ Signs: attestation quote │
└────────────────────────────┘
- TEE: 데이터를 안전하게 읽고 hash/attest 생성
- ZKP: TEE가 서명한 데이터를 witness로 사용해 증명 생성
- Contract: proof와 attestation을 함께 검증
처럼 이해하면 크게 어렵지 않을 것이다.
Part 4. 운영 및 보안 조건
아래는 아주 짧은 시간동안 고민해본 보안 고려 사항으로, 단순 참고만 해주세요.
- Trusted Setup : MPC Ceremony/toxic waste 반드시 제거할 것.
- TEE Attestation : 키체인 관리가 철저히 할 것.
- Side-channel Attack : TEE는 하드웨어 기반 기능이고, 하드웨어는 Side-channel attack에 취약하기 마련. 방어책을 세울 것.
- Nullifier : double-spend를 방지하기 위해서, nullifier는 단 한번만 사용 가능하도록, Contract에 별도의 Mapping을 두고 검사할 것.
결론
ZKP는 연산의 정당성을 보장하지만, 입력의 진실성은 보장하지 않는다. TEE는 입력의 진실성을 보장하지만, 연산의 정당성은 보장하지 않는다.
이 둘이 결합할 때 비로소 완성된다.
| 기술 | 보장하는 것 | 보장하지 않는 것 |
|---|---|---|
| ZKP | 연산의 정당성 | 입력의 진위성 |
| TEE | 입력의 진위성 | 연산의 정당성 |