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 흐름

  1. 사용자(증명자)는 TEE(추후 설명) 내부에서 비밀값(balance, sk, nonce)을 로드
  2. 회로(balance ≥ amount, MerklePath(leaf)==root) 만족 여부를 검증
  3. 증명 생성 (Groth16, PLONK 등)
  4. proof + public inputs(root, amount, nullifier 등)를 온체인 컨트랙트에 제출
  5. 검증 컨트랙트가 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)” 은 보장하지 않는다.

즉, 아래 두 문제를 스스로는 해결할 수 없다.

  1. 입력이 실제 존재하는 데이터인가? (예: balance를 임의로 조작해도 회로만 맞으면 증명 생성 가능)

  2. 입력이 노출되면 어떻게 되는가? (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 입력의 진위성 연산의 정당성