返回 Expert 笔记
Expert Day 259

ZK隐私交易系统 — 需求与架构设计

监管后的隐私设计、Tornado/Aztec/Privacy Pools v2取舍、PRD写作

2027-01-15
Phase 4 - 综合项目 (Day 259-263)
ZK隐私实战项目架构设计PrivacyPools合规

日期: 2027-01-15 方向: ZK综合项目 / 隐私交易系统 阶段: Phase 4 - 综合项目 (Day 259-263) 标签: #ZK #隐私 #实战项目 #架构设计 #PrivacyPools #合规


今日目标

类型内容
学习监管后的隐私设计、Tornado/Aztec/Privacy Pools v2取舍、PRD写作
实操写完整PRD + 系统架构图 + 8个关键trade-off决策表
产出docs/zk-priv-tx/PRD.md(本笔记承载草案)+ architecture.png 草图

1. 项目背景与定位

1.1 为什么做这个项目(Why now)

经过 Day 181-258 的密码学与 ZK 基础训练(field/curve/pairing → Groth16/PlonK/STARK → FHE/MPC/TEE → Privacy Pools v2),我已经具备实现一个端到端隐私交易系统的能力。但单纯重写 Tornado Cash 已经没有意义——市场上现存方案各有问题:

系统状态问题
Tornado Cash2022 OFAC制裁,2025年部分撤销,创始人仍在司法纠纷无合规层、零任意可分级、所有人混一锅
Aztec Connect2024年3月关闭团队主动关闭,"无法同时满足合规与隐私"
Aztec Network (Noir)2026年mainnet自有L2、生态独立、accountcontract复杂
Privacy Pools v2 (0xbow)2023年上线、2026 TVL ~$15M仅 ETH,UI体验仍需改进,单一 ASP(Chainalysis)
Railgun2021年至今、活跃自定义 nullifier / shield 设计,code review 复杂

我的项目(v0.1)定位

"Tornado-like UX + Privacy Pools v2 合规模型 + 多 ASP 可插拔 + Relayer 网络"

一个 EVM L2(先 Sepolia → Base/Arbitrum)上的固定面额隐私存提款池,用户可在 deposit 后选择任意 ASP(含 self-attest),withdraw 时通过 ZK 证明 (pool inclusion + ASP inclusion + nullifier)。

为什么这是好项目

  1. 学习价值最大:把 Day 223-227(Circom + mini Tornado)+ Day 256(Privacy Pools v2)+ Day 244-258(FHE/MPC/TEE)三条线收束成一个可运行系统。
  2. 简历价值高:Tornado 创始人坐牢 + Aztec 关闭 + 0xbow 上线 这三件事让"懂合规隐私"成为稀缺技能;2026年下半年所有 RWA / 机构 DeFi 都需要这个能力。
  3. 可控复杂度:固定面额(避免 amount-hiding)+ Groth16(避免 PlonK 工具链)+ EVM(避免 L2 自研),5天可实现 MVP。

1.2 vs 现有方案

维度Tornado CashPrivacy Pools v2 (0xbow)我的项目 v0.1
隐私完全无差别混集合内匿名集合内匿名(同 PPv2)
合规单一ASP(Chainalysis)多ASP,用户可选+自荐
面额固定(1/10/100 ETH)固定固定 1 ETH(v0.1)
Relayer中心化relayer中心化relayerRelayer注册表 + gas refund
Tree depth202020
证明系统Groth16Groth16Groth16(snarkjs)
MainnetMainnetSepolia → Base
OFAC风险已被制裁主动配合主动配合(不接收 SDN)

注:我们的设计不发币、不收费、纯学习项目,但代码与 PRD 按生产标准对待。


2. 产品需求 PRD

2.1 用户故事(5个)

US-1:合规隐私存款(白领用户 Alice)

作为 一个想保护交易隐私的合法收入者
我想要 把 1 ETH 存入隐私池,未来某天匿名取出
以便   我的工资地址不被链上对手长期追踪

接受标准:
- 我能在 60 秒内完成 deposit
- 我得到一份 note.json (本地保存)
- deposit tx 在区块浏览器只显示 commitment, 不暴露 nullifier
- gas 成本 < $5 (Sepolia / L2)

US-2:合规隐私取款(同一 Alice,3个月后)

作为 持有 note.json 的用户
我想要 把池中那 1 ETH 取到一个新地址 Bob
以便   Bob 地址与我原 Alice 地址在链上不可关联

接受标准:
- 我能在浏览器选择 ASP(如 "Chainalysis no-SDN")
- 证明生成 < 30 秒(笔记本电脑)
- 取款 tx 不暴露 Alice 地址,只暴露 nullifierHash 和 ASP root
- gas < 500k
- 如果 ASP 不包含我的 deposit,UI 提示我换一个 ASP

US-3:Relayer 提款(无 ETH 用户 Carol)

作为 在 Bob 新地址上没有 ETH 付 gas 的用户
我想要 让 relayer 替我发 withdraw tx
以便   我不需要先从 CEX 转 ETH 到新地址(这会产生关联)

接受标准:
- 我能从公开 relayer 列表选一个 (UI 显示费率)
- 我不暴露自己 IP 给 relayer (用 Tor 或 mixnet — v0.2)
- relayer 不能更改 recipient 字段(电路绑定)
- relayer fee 透明显示,且 ≤ 5% denomination

US-4:ASP 运营商(合规公司 ChainGuard)

作为 一家做链上风控分析的公司
我想要 发布 "no-SDN, no-mixer-funded" association set
以便   我的客户(机构)能合规使用此 pool

接受标准:
- 我能 register 自己的 ASP 合约地址
- 我能每天 update Merkle root
- 我的更新被链上事件记录,可审计
- 用户能查询 "commitment c 是否在我的 ASP set"

US-5:监管/审计员(FinCEN 调查员 Dave)

作为 政府合规调查员,对一笔可疑交易展开调查
我想要 验证某 withdraw 关联的 ASP 是否包含SDN地址
以便   评估池子是否有意为洗钱提供服务

接受标准:
- 我能查 withdraw tx → ASP root → ASP provider
- 我能让 ASP provider 提供其 set 全集(链下,根据法律请求)
- 我看到的是 "ASP 选择政策",而非用户身份

2.2 核心功能(FR-1 到 FR-5)

ID功能描述优先级
FR-1Deposit用户提交 commitment,池子接收 1 ETH,更新 Merkle treeP0
FR-2Withdraw with ASP用户提供 (ZK proof, pool root, asp root, nullifier hash, recipient, relayer, fee),池子验证后转账P0
FR-3ASP Registry任何人可注册 ASP;ASP定期 update rootP0
FR-4Relayer Registry任何人可注册 relayer;用户从 UI 选P1
FR-5Note encryption用户的 note (nullifier+secret) 用 password 加密保存P1

2.3 非功能需求(NFR)

ID类别指标备注
NFR-1性能-gasdeposit ≤ 250k gas含 Merkle insert
NFR-2性能-gaswithdraw ≤ 500k gas含 Groth16 verify + 2 Merkle root check
NFR-3性能-proof客户端生成 ≤ 30s普通笔记本(M1 / Ryzen 5)
NFR-4安全所有合约通过 Slither 无 CriticalCI 强制
NFR-5安全电路通过 circom-pairing 静态检查under-constrained 检测
NFR-6合规不接收已知 OFAC SDN deposit链下 KYT 拒绝(v0.2 可加链上检查)
NFR-7可用性移动浏览器可用Mobile Safari/Chrome 测试
NFR-8监控关键事件全部 emit eventindexer 可解析

2.4 范围外(v0.1 不做)

  • ❌ 多面额(仅 1 ETH)
  • ❌ ERC20(仅 native ETH)
  • ❌ 跨链(仅单链)
  • ❌ Shielded transfer pool 内部转账(仅 deposit→withdraw)
  • ❌ 自研 relayer 网络(用现有 ethers.js + 单 relayer)
  • ❌ Mobile native app(仅 web)

3. 系统架构

3.1 整体架构图

┌─────────────────────────────────────────────────────────────────┐
│                         USER (Browser)                           │
│  ┌────────────┐   ┌────────────┐   ┌──────────────────────┐    │
│  │ Deposit UI │   │Withdraw UI │   │ Note Manager (local) │    │
│  └─────┬──────┘   └──────┬─────┘   └──────────────────────┘    │
│        │                 │                                       │
│  ┌─────┴─────────────────┴─────┐                                │
│  │   Wallet (RainbowKit)       │                                │
│  └────────────┬────────────────┘                                │
│               │                                                  │
│  ┌────────────┴───────────────────────────────────────────┐    │
│  │   Proof Engine (snarkjs WASM)                          │    │
│  │   - witness from (n, s, path, asp_path)                │    │
│  │   - groth16.fullProve()                                │    │
│  └────────────┬───────────────────────────────────────────┘    │
└───────────────┼──────────────────────────────────────────────────┘
                │
        ┌───────┴────────┐                  ┌─────────────────┐
        │                │                  │                  │
        ▼                ▼                  ▼                  ▼
┌──────────────┐  ┌─────────────┐    ┌──────────────┐  ┌────────────┐
│ Direct call  │  │  Relayer    │    │  ASP Provider│  │ Indexer/UI │
│ (own gas)    │  │  Service    │    │  (off-chain) │  │ (subgraph) │
└───────┬──────┘  │             │    │              │  └────────────┘
        │         │ - holds key │    │ - watches    │
        │         │ - relays    │    │   pool events│
        │         │   tx for fee│    │ - updates    │
        │         └──────┬──────┘    │   Merkle root│
        │                │           │   on-chain   │
        │                │           └───────┬──────┘
        ▼                ▼                   ▼
┌─────────────────────────────────────────────────────────────────┐
│                         BLOCKCHAIN (Sepolia)                     │
│  ┌────────────────┐    ┌─────────────────┐                      │
│  │  PrivacyPool   │ ◄──│   Verifier      │                      │
│  │  - deposit()   │    │ (Groth16 auto-  │                      │
│  │  - withdraw()  │    │  generated)     │                      │
│  │  - merkle root │    └─────────────────┘                      │
│  │  - nullifiers  │                                              │
│  └────┬───────────┘                                              │
│       │                                                          │
│  ┌────┴─────────────┐    ┌───────────────────┐                  │
│  │ ComplianceOracle │    │  Relayer Registry │                  │
│  │ - ASP registry   │    │  - registered     │                  │
│  │ - admin pause    │    │    relayers       │                  │
│  └──────────────────┘    └───────────────────┘                  │
└──────────────────────────────────────────────────────────────────┘

3.2 组件清单

组件类型文件职责
deposit.circomCircuitcircuits/验证 commitment = Poseidon(n,s)
withdraw.circomCircuitcircuits/主电路:Merkle inclusion + ASP inclusion + nullifier
asp_membership.circomCircuitcircuits/子电路:单独验证 ASP membership(可独立 audit)
Verifier.solContractcontracts/snarkjs 自动生成
PrivacyPool.solContractcontracts/deposit / withdraw / Merkle tree state
ComplianceOracle.solContractcontracts/ASP 注册、root publishing
Relayer.solContractcontracts/relayer 注册、fee schedule
proof.tsClientclient/witness + proof generation
merkle.tsClientclient/本地构造 Merkle path
relayer.tsClientclient/call relayer service

3.3 数据流(withdraw 关键路径)

1. User → ProofEngine:
     {
       nullifier, secret,                    // private
       merklePath (20 levels),               // private (从 indexer 拿)
       aspPath (20 levels),                  // private
       root, aspRoot, recipient,             // public
       relayer, fee, refund                  // public
     }

2. ProofEngine → snarkjs.groth16.fullProve():
     proof = (a, b, c)
     publicSignals = [root, aspRoot, nullifierHash, recipient, relayer, fee, refund]

3. User chooses path:
   3a) Direct: ethers.js → PrivacyPool.withdraw(proof, publicSignals)
   3b) Relayer: HTTP POST → relayer service → relayer ETH wallet → withdraw()

4. PrivacyPool.withdraw() flow:
     a. require(!nullifiers[h])
     b. require(isKnownRoot(root))
     c. require(complianceOracle.isKnownAspRoot(aspRoot))
     d. Verifier.verifyProof(proof, publicSignals)
     e. nullifiers[h] = true
     f. transfer(recipient, 1e18 - fee)
     g. transfer(relayer, fee)
     h. emit Withdraw(h, recipient, relayer)

4. 关键设计 Trade-off

TO-1: Tornado-style 单池 vs Privacy Pools v2 多 ASP

选项
A. Tornado-style 单池实现简单、用户体验好无合规、被监管制裁风险高
B. PPv2 多 ASP合规可分级、用户可选多一层 Merkle proof(电路约束 ↑)

决策:B。原因:

  1. 监管现实:2026年Sepolia部署不会被制裁,但写入简历的项目"主动设计合规"是必备特征。
  2. 学习价值:双 Merkle proof 是 ZK 工程关键技能(一次电路里两棵树 inclusion)。
  3. 性能:PPv2 论文数据 + 我的预估,多一棵 20 层 Merkle 约 +800 constraints,proof time +3秒,可接受。

TO-2: Circom 2 vs Noir

选项
A. Circom 2 + snarkjs工具链最成熟、Tornado/PPv2同栈、Day 223-227 已熟DSL 老旧、调试痛苦
B. Noir + bb (Aztec)现代 DSL、Rust-like、auto-formal-verify工具链 2026 仍在演进、与 Sepolia 集成需 Aztec.js

决策:A。原因:

  1. 5 天 MVP 时间预算下,工具链稳定性 > 语法美观。
  2. 与 Day 223-227 工程衔接顺畅,可复用 MerkleTreeChecker。
  3. Noir 留给 v0.2(独立项目)。

TO-3: Groth16 vs PlonK

选项
A. Groth16proof 192 bytes、verify ~250k gas、tooling最稳每电路独立 trusted setup
B. PlonK (Halo2/Plonky2)universal setup、可升级电路proof 大(~500 bytes)、verify gas高(~400-500k)、tooling 复杂
C. STARK无 trusted setup、post-quantumproof 巨大(10s of KB)、链上 verify ~2M+ gas

决策:A。原因:

  1. NFR-2 限定 withdraw ≤ 500k gas,Groth16 verify ~250k 给业务逻辑留充足预算。
  2. v0.1 电路冻结,trusted setup 一次性问题(用 Hermez ptau 或 PowersOfTau 社区仪式)。
  3. PlonK 的 universal setup 优势对单一电路项目无意义。

TO-4: On-chain ASP root vs Off-chain KYT

选项
A. ASP root 上链透明、可审计、电路直接消费ASP 必须发 tx 更新 root(gas 成本 + 延迟)
B. ASP 链下 + 用户带签名ASP 不发 tx、灵活用户需获取 ASP 签名、replay 风险、合约需 EIP-712 verify
C. 完全链下 KYT(用户跳过 ASP, deposit 时被 review)无需电路改动与 PPv2 范式相悖、退回 Tornado 模型

决策:A。原因:

  1. v0.1 我们重点演示 PPv2 设计,A 是教科书路径。
  2. ASP root 上链频率低(每天/每周),gas成本可控(每次 ~50k)。
  3. 链上发布 + event log = 完美的"监管审计trail"。

TO-5: Relayer 信任模型

选项
A. 中心化单 relayer实现最简单点故障 + 地址关联风险
B. Relayer Registry + 客户端选择用户可选 + 抗审查UI 复杂度 ↑
C. 去中心化 relayer 网络(如 PSE Mixnet)强抗审查跨项目集成成本巨大

决策:B。原因:

  1. v0.1 时间预算下,Registry 是 Tornado 已验证的模式(虽然 Tornado 实际只一个 relayer 主导)。
  2. 在合约层留 hook(registry.isRegistered(relayer)),客户端只展示注册过的。
  3. v0.2 可以接 Waku/PSE mixnet。

TO-6: 固定面额 vs 任意面额

选项
A. 固定 1 ETH隐私集合最大、电路无 amount-hiding灵活性差
B. 多档面额(1/10/100)适配不同用户拆分隐私集合
C. 任意面额(hidden amount)灵活需 Pedersen / range proof,电路复杂度 ×3

决策:A。Tornado/PPv2 都是固定面额,v0.1 无理由偏离这个最佳实践。

TO-7: Note 客户端管理

选项
A. 用户自己保存 note.json简单丢失=资金丢失
B. 加密 + 用户密码 + IndexedDB体验好、支持多设备同步(v0.2)增加 password UX
C. 服务器托管(加密)体验最好中心化、合规风险

决策:B。用 password + AES-GCM 加密 note,存 IndexedDB。

TO-8: Merkle tree 实现选择

选项
A. 自实现 Incremental Merkle TreeDay 224 已有代码bug 风险
B. Semaphore IncrementalBinaryTree.sol经审计、广泛使用Solidity依赖
C. zk-kit / lean-imt优化版接口与 Tornado 不同

决策:B。Semaphore 团队的 IMT 库已被 Worldcoin / Privacy Pools 等项目使用,经审计。


5. 风险与合规

5.1 OFAC 前车之鉴(Tornado Cash)

时间事件教训
2022-08-08OFAC 把 Tornado Cash 智能合约地址列入 SDN合约本身可被制裁(不只是人)
2022-08-12Alexey Pertsev (开发者) 在荷兰被捕开发者面临个人刑事风险
2024-05-14Pertsev 被荷兰法院判 5年4月即使代码是开源、用户匿名,开发者仍被认定"明知洗钱"
2025-03第五巡回上诉法院裁定OFAC对智能合约制裁不合宪但限制限于"不可变合约"
2025-08Roman Storm 美国陪审团 deadlock,部分罪名待重审法律风险长期化

5.2 我们的风险缓解

风险缓解措施
OFAC 把合约列 SDN仅 Sepolia 部署、个人学习项目、不上 mainnet
被认定提供"无牌经营 money transmitter 服务"不收手续费、不运营 relayer、不承担 KYC 责任
合规层失效(用户绕过 ASP)合约层强制 require(asp.isKnownRoot(aspRoot)),电路层强制 ASP inclusion
监管要求"披露用户身份"ASP provider 是法律主体,自行处理;池子合约不存任何 PII
资金被洗钱使用合约不可暂停 deposits(避免成为 honeypot),但 admin 可标记某 commitment "frozen" — v0.2

5.3 法律免责(README 必须包含)

## ⚠️ Legal Disclaimer

This project is a research/educational reference implementation of
"Privacy Pools v2" architecture, deployed on Sepolia testnet only.

**Not for production use.** **Not for handling real funds.**

The author makes no warranty regarding the legal status of using
privacy-preserving cryptocurrency tools in any jurisdiction.

If you use this code in production:
- You are responsible for KYC/AML compliance in your jurisdiction
- You are responsible for OFAC sanctions compliance
- You should consult licensed legal counsel
- The author bears no liability whatsoever

6. MVP 范围(v0.1,5天)

Day内容交付
Day 259 (今天)需求 + 架构PRD.md + architecture.png
Day 260Circom 电路实现deposit/withdraw/asp_membership.circom + tests
Day 261Solidity 合约实现4 个 .sol + Hardhat tests
Day 262前端集成Next.js + RainbowKit + snarkjs WASM
Day 263端到端测试 + 部署 + READMESepolia 部署 + demo 视频脚本

6.1 v0.2 路线图(不在 5 天内)

  • ERC20 支持(USDC/DAI 池)
  • Shielded internal transfer
  • Mobile native app (React Native)
  • 接入 Aztec.js / Noir 重写电路对比 benchmark
  • L2 部署 (Base Sepolia → Base mainnet — pending legal review)
  • Relayer 去中心化(Waku / PSE mixnet)
  • Multi-asset ASP(同 ASP 跨多个 pool)

7. 项目目录结构

zk-privacy-tx/
├── circuits/
│   ├── deposit.circom
│   ├── withdraw.circom
│   ├── asp_membership.circom
│   ├── lib/
│   │   ├── merkle.circom        # Day 224 复用
│   │   └── poseidon_alias.circom
│   └── tests/
│       └── withdraw.test.js
├── contracts/
│   ├── Verifier.sol             # 自动生成
│   ├── PrivacyPool.sol
│   ├── ComplianceOracle.sol
│   ├── Relayer.sol
│   └── lib/
│       └── IncrementalBinaryTree.sol  # @zk-kit/imt
├── scripts/
│   ├── deploy.ts
│   ├── deposit.ts
│   ├── withdraw.ts
│   └── update_asp_root.ts
├── client/
│   ├── proof.ts
│   ├── merkle.ts
│   ├── relayer.ts
│   └── utils.ts
├── components/
│   ├── DepositForm.tsx
│   ├── WithdrawForm.tsx
│   └── NoteManager.tsx
├── pages/
│   ├── index.tsx
│   ├── deposit.tsx
│   └── withdraw.tsx
├── relayer-service/             # 独立 Node.js 服务
│   ├── server.ts
│   └── package.json
├── test/
│   ├── PrivacyPool.test.ts
│   └── e2e.test.ts
├── hardhat.config.ts
├── next.config.ts
├── package.json
└── README.md

8. 性能预算(NFR 量化)

8.1 Gas 预算(基于 Tornado Cash 实测:deposit 1.1M, withdraw 360k)

操作目标Tornado对比备注
deposit()≤ 250k1.1M用 IncrementalBinaryTree.sol(更优)
withdraw()≤ 500k360k多一次 ASP root 检查(+10k)
registerASP()≤ 80kn/a一次性
updateAspRoot()≤ 50kn/a频繁(每天)
registerRelayer()≤ 100kn/a含 stake

Tornado 1.1M deposit 主因是手写 IMT。Semaphore 库实测可降到 200-250k。

8.2 Proof time 预算

电路constraints (估)proof time (M1 笔记本)
deposit (sanity check)~500<1s
withdraw~10000~15-25s
asp_membership (子电路)~3000~5-8s

Tornado 实测:~7000 constraints, ~10-15s in browser. 我们多一棵树 → +800 constraints 估计可接受。


9. 明日预告

Day 260: Circom 电路实现

明天我们将:

  • 写完整的 deposit.circom(commitment 生成)
  • 写完整的 withdraw.circom(核心电路:Merkle proof + ASP membership + nullifier)
  • asp_membership.circom(子电路)
  • 用 circom_tester + jest 写单元测试
  • 选择 trusted setup ceremony(用 Hermez pot15_final.ptau

预计代码量:~400 行 Circom + ~200 行测试

风险:under-constrained signal 是 Circom 头号 bug 来源(recipient/relayer/fee 在我们电路里只 binding 用,必须用 quadratic constraint 约束,否则 prover 可以替换)。这是 Tornado Cash 早期电路的真实问题之一。


10. 今日复盘

学到的

  • PRD 不是简单功能列表,而是 user story + functional + non-functional + scope-out 的完整闭环
  • Trade-off 决策的本质是"明确放弃什么"(如选 Groth16 即放弃可升级电路)
  • 合规设计 ≠ 监管讨好;PPv2 的设计是"让善意用户主动选合规子集",本质上是用户主权设计
  • Tornado / Aztec / Privacy Pools 三者的命运反映了 2022-2026 行业的监管学习曲线

卡点

  • 多 ASP 在 UI 上如何呈现仍未想清楚(用户教育成本高)
  • v0.2 的 mobile 体验需要 mobile WASM proof gen,目前 snarkjs 在 mobile 浏览器表现未知

与未来工作连接

  • Day 89-90 求职冲刺:本项目可作为"zk-engineer + privacy-PM"双标签作品
  • Day 264+ 论文精读:把今天的设计与最新论文(2027 Q1 任何隐私池新论文)对照

引用

  • Day 223-227: Circom 基础 + mini Tornado 实现
  • Day 244-258: FHE/MPC/TEE 综合,Day 256 是 Privacy Pools v2 论文精读
  • Buterin V., Illum J., Nadler M., Schär F., Soleimani A. (2023). "Blockchain Privacy and Regulatory Compliance: Towards a Practical Equilibrium." SSRN.
  • Tornado Cash whitepaper (2019). "Tornado.Cash Privacy Solution Version 1.4."
  • 0xbow.io documentation (2023-2026). "Privacy Pools — Compliance Architecture."
  • Aztec Labs (2024-03). "Aztec Connect Sunset Announcement."
  • Semaphore Protocol (2023). "IncrementalBinaryTree.sol audit by ABDK."