25 / 11 / 06
以下是对 Privacy Cash(也称 “zkcash”)协议在 Solana 链上实现的深度阅读与分析,重点涵盖其技术细节、核心概念及实现原理。本文尽可能清晰地呈现架构、加密机制、UTXO 模型、零知识证明流程、Merkle 树、nullifier 等。若有部分细节在源码或文档中略有省略,我会标注“资料所限”之处。
根据其官方 wiki,Privacy Cash 是一个在 Solana 上构建的隐私协议,允许用户将 SOL 代币(Solana 本链原生代币)存入一个共享隐私池(shielding),然后可从该池中向任意地址提款,而无需公开存款地址与提款地址之间的关联。 (DeepWiki )
存入 (“Shield SOL”):用户将 SOL 存入隐私池,生成一个承诺 (commitment) 并加入 Merkle 树。 (DeepWiki )
提款 (“Withdraw SOL”):用户通过零知识证明 (zk-SNARK) 验证其对某存款 UTXO 的所有权及未被消费状态,从池中提取至任意地址,而无需公开其原始存款关联。 (DeepWiki )
设计目标:隐匿存款-取款之间的链上可观测关联,同时保证系统正确性(未双花、金额守恒、生成的新 UTXO 合法等)。 (DeepWiki )
此协议还显示其称为“符合 Office of Foreign Assets Control (OFAC) 合规”的隐私协议。 (Coinfomania )
下面分条说明其关键技术组件与概念。
协议中提到几个核心机制:
Commitments(承诺):用于隐藏 UTXO(未花费输出)所属者、公钥、金额、盲因子(blinding factor)等。wiki 中以 “Hash(amount, public_key, blinding_factor)” 为例。 (DeepWiki )
Nullifiers(空化器):用于防止双重支付。每当一个 UTXO 被花费(withdraw)时,其对应的 nullifier 被公开或加入记录,以防再次花费。wiki 里注明:“Hash(commitment, merkle_path, signature)” 作为 nullifier。 (DeepWiki )
Merkle 树:存储所有承诺 (commitments) 的根结构,用于生成包含证明 (membership proofs)。wiki 中提到 “Sparse tree of height 26” 作为示例高度。 (DeepWiki )
零知识证明 (Zero-Knowledge Proofs):协议采用 zk-SNARKs(Groth16)来证明用户对某承诺/UTXO 的所有权、未被消费状态、以及金额守恒等,而不会泄露其具体输入/输出、地址、金额等。 (DeepWiki )
协议不是账户模型,而类似于 UTXO 模型(未花费输出)。wiki 描述如下:
每次存款 (deposit) 会创建一个或多个新的 UTXO(承诺),并加入 Merkle 树。 (DeepWiki )
提款 (withdraw) 消耗(花费)现存 UTXO,并(如有找零)创建新的 UTXO。 (DeepWiki )
所有 UTXO 的实际数据(金额、所有者私钥等)加密或存储在链下,链上仅存储承诺哈希与根等。 “Only commitment hashes are stored on‐chain in the Merkle tree.” (DeepWiki )
wiki 提到协议使用 Groth16 zk-SNARK,需要一个可信设置的多方礼仪 (multi-party ceremony) 来生成证明密钥(proving key)与验证密钥(verifying key)。只要参与者中至少一人销毁其秘密,设置即安全。 (DeepWiki )
wiki 列出若干组件:
zkCash Solana Program(链上程序/智能合约)
Indexer Service(用于索引 UTXO 承诺、nullifier 等)
Webhook Processing / Data Services / Client Scripts
Transaction Processing / UTXO Management & Encryption
这些组件合起来支持从用户界面到链上程序、隐私池管理、脱链存储、证明生成与验证。 (DeepWiki )
下面逐项深入说明协议在实现时的技术细节。
用户选择要“屏蔽”的 SOL 数量。
用户生成一个新的 UTXO,内部原理通常包括:
随机生成一个 “盲因子” 或 “秘密随机数” (blinding factor) 和(可能)一个密钥对或公钥。
使用哈希函数对 (金额, 接收者公钥?, 盲因子) 生成一个“承诺”(commitment)。Wiki 给出的简化形式为 Hash(amount, public_key, blinding_factor). (DeepWiki )
将这个承诺作为叶子插入 Merkle 树中。链上只存入该承诺哈希与更新后的 Merkle 根 (或提交后可检索的根)。
用户将 SOL 发送到隐私池。程序将该金额锁定(或转入池合约中)。存款操作不公开用户地址与投入资产的来源与目的。
用户保存该 UTXO 的私密信息(即盲因子、相关 witness、Merkle 路径等),以备将来提款。
用户希望将资金从隐私池提款到某目标地址。
用户从其保存的 UTXO 私密数据出发,生成一个零知识证明 (proof),该证明通常需要满足:
我知道一个 UTXO(即某叶子的承诺)在当前 Merkle 树中(membership proof)——即该承诺属于隐私池。
我知道承诺对应的秘密盲因子/所有权数据,从而我有权花费该 UTXO。
我没有曾用于花费(即相应的 nullifier 尚未被使用)——防止双花。
如果有 “找零” 输出,新创建的 UTXO 合法、金额守恒(输入金额 = 输出金额 + fee)。
用户向链上提交提款交易,其中包括:证明 (proof)、根 (root) 或相关 Merkle 路径、nullifier 或 nullifier 哈希、目标提款地址、(如有)找零输出的承诺等。
链上程序(合约/Solana 程序)验证:
提交的 root 在其状态中是最新/合法的。
证明有效(使用验证密钥验证 zk-SNARK)。
提交的 nullifier 尚未使用(未记入 nullifier 集合)。
若成立,则程序标记该 nullifier 为已使用,释放资金至目标地址,并(如有)将找零 UTXO 的承诺插入 Merkle 树。
链上状态更新,同时真实的 UTXO 消耗被隐匿(无法链上直接追踪原 UTXO 与提款地址关联)。
Merkle 树:承诺 (commitments) 被组织进一个 Merkle 树。用户需要知道自己的叶子位置和相应的 Merkle 路径,以便在证明中使用 membership proof。Wiki 提到“Sparse tree of height 26”作为示例。 (DeepWiki )
Nullifier:当用户提款时,生成一个 nullifier(通常从秘密中派生),并将该 nullifier(或其哈希)提交链上以标记该 UTXO 已被花费。这样可有效防止双花,因为同一个 nullifier 不能重复使用。 Wiki 中 “Hash(commitment, merkle_path, signature)” 作为生成 nullifier 的一个形式。 (DeepWiki )
双花防范:通过链上的 nullifier 集合(或类似结构),每次提款前检查 nullifier 是否已存在。若存在,则拒绝提现。此机制类似于 Zcash 等隐私协议中采用的方式。 (Learn Blockchain )
找零 (change-outputs):如果用户存入的 UTXO 金额大于提款金额 + fee,系统可能产生新的 UTXO(找零)并插入树中,从而维持金额守恒且增强混淆。Wiki 简要提及 “create new ones (if change is needed)”. (DeepWiki )
协议使用 Groth16 zk-SNARK。Wiki 明确指出 “Groth16 zk-SNARKs”。 (DeepWiki )
需要进行可信设置 (trusted setup),即多参与者礼仪生成 proving key 和 verifying key。Wiki:“Multi-party ceremony with multiple contributors … Generates proving and verifying keys”. (DeepWiki )
证明电路的设计应包括:承诺所属证明(membership)、未花费证明(nullifier 未使用)、金额守恒、合法输出等。虽然 wiki 文档没有披露电路具体代码,但基于类似协议 (如 Zcash) 的实践我们可以推断设计模式。参考 Zcash 的电路流程:将交易语句转换为多项式约束系统,再通过 SNARK 生成与验证。 (WEBKT )
哈希函数:为了 SNARK-友好 (ZK-friendly),隐私协议通常选用特定哈希算法(例如 MiMC、Pedersen、Poseidon)以降低电路复杂度。虽然 wiki 中未明确说明使用的哈希,但参考类似方案 (如 Tornado Cash) 的做法:commitment = Pedersen/ MiMC 的哈希。 (登链社区 )
由于该协议在 Solana 上运行,有几点需要注意:
Solana 的机制(程序、账户、指令模型)不同于以太坊。Protocol 必须适配 Solana 的账户/程序架构。
链上只存储承诺哈希/Merkle 根/nullifier 状态,而敏感数据(例如盲因子、私钥、Merkle 路径)在用户端或脱链存储。Wiki 指出 “All sensitive data remains client-side or encrypted”. (DeepWiki )
索引服务 (Indexer Service) 用于跟踪提交的承诺、树结构、nullifier 使用情况,以便程序或用户查询。
合规机制:协议宣称符合 OFAC 合规,这可能意味着程序可能集成审查或黑名单检查机制(例如黑名单地址过滤、提款限额、审计日志)以满足监管要求。尽管技术细节未公开,但这是一个设计考量。 (Coinfomania )
用户隐私增强:通过承诺 + 零知识证明 + UTXO 模型,用户存款与提款之间的链上关联被削弱。
资产守恒与安全性:UTXO 模型、nullifier 防双花、SNARK 证明机制都增强系统可信度。
可植入合规设计:该协议强调 OFAC 合规,这对于主流区块链生态(如 Solana)向机构用户开放隐私服务是一个亮点。
可在高速链(Solana)上运行:借助 Solana 高吞吐、低延迟特性,有潜力实现更实际的隐私交易。
可信设置风险:使用 Groth16 SNARK 的可信设置如果被破坏(所有参与者泄露其秘密),可能导致系统安全性受损。Wiki 已提及可信设置多个贡献者。 (DeepWiki )
匿名集 (anonymity set) 限制:即便使用混池机制,匿名集大小可能受限,从而削弱隐私效果。已有研究指出即便是 Tornado Cash 等协议也存在这类风险。 (arXiv )
监管与合规压力:隐私交易协议可能面临监管监控或制裁,尤其当用于混洗非法资金时。该协议虽注明合规,但操作细节仍可能引起质疑。
脱链数据(如盲因子、用户私钥、Merkle 路径)管理风险:如果用户保存不当,这部分敏感信息泄露可能破坏隐私。
实现与部署难度:在 Solana 上实现低延迟、高吞吐、维护树状态、索引服务、证明生成等具有技术挑战。
为了理清流程,下面用文字描述一个简化的端到端交易流程:
用户 A 决定向用户 B 付款,并希望隐藏中间关联。
步骤 1:A 生成一个承诺 C₁ = Hash(amount = X, A_pubkey, blinding_factor).
步骤 2:A 将 X 个 SOL 转入隐私池(合约/程序锁定)。程序将 C₁ 插入 Merkle 树,更新根 R.
步骤 3:A 保留私密数据 {blinding_factor, A_pubkey, leaf_index, Merkle_path_to_R}.
步骤 4:当 A 决定提款给 B 时,A 生成 SNARK 证明 π,证明其知晓某承诺 C₁ 在树 R 中、其对应秘密是正确、相应 nullifier N₁ 尚未被使用、以及输出金额合法。
步骤 5:A 提交提款交易,包括 {π, R, N₁, B_address}.
步骤 6:链上程序验证 π (用验证密钥)、确认 N₁ 未使用、确认 R 为当前树根、然后:
标记 N₁ 为已使用(防双花)
将 X SOL 发送至 B_address
若有找零 (例如 X > Y) 则生成新的承诺 C₂ = Hash(amount= X–Y–fee, A_change_pubkey, blinding_factor2) 插入树并给 A 。
用户 B 收到 SOL,但链上无法直接看出它来自 A。
Privacy Cash 利用经典的隐私协议构建方式(UTXO,承诺,nullifier,Merkle 树,zk-SNARK)在 Solana 生态中实现私密转账功能。其优势在于隐私保护、合规强调、高速链适配。但同时也面临可信设置、安全管理、匿名集规模、监管挑战等问题。