ZEX 协议旨在实现无需协议级修改或协同处理器的隐私保护型 DeFi 交易。它基于 cWETH 模型的保密代币,通过引入保密额度,实现点对点交易,并利用椭圆曲线加密和 zk-SNARKs 技术来验证余额更新的正确性,从而在不泄露实际交易金额的情况下保护用户隐私。该协议虽然在用户体验和 gas 消耗方面负担较重,但提供了一种无需许可的保密 DEX 的早期概念验证。
解锁隐私保护的DeFi。无需协议级别的修改,也无需辅助处理器即可运行ZEX。虽然在用户体验方面(以及gas消耗方面)负担很重,但这只是一个早期的PoC草案。任何反馈都将非常有价值!
ZEX协议构建于cWETH保密代币模型之上。请在继续之前先查看一下。
以太坊的透明性,虽然是其最有价值的优势之一,但已成为现实世界金融采用的障碍。公共区块链默认公开余额、授权、交易对手,甚至代币获取情况。
本提案介绍了ZEX,一种使用cWETH作为保密代币模型的,无需许可且保密的点对点去中心化交易所(DEX)机制。它通过保密的授权额度扩展了代币的功能,从而实现隐藏的点对点交互。与cWETH协议类似,ZEX逻辑利用基于椭圆曲线(EC)扭曲ElGamal的承诺方案来确保保密性,利用EC Diffie-Hellman(DH)来引入价值可访问性,并利用zk-SNARK来验证代币授权和转移过程中余额更新的正确性,而无需透露实际交换的金额。
ZEX协议充当交换报价的市场,其中交换以三步交互方式进行,并且需要在同一交易中验证多个ZK证明。ZEX披露的唯一信息是价格和初始报价授权额度,表明可用于特定交换的最大代币数量。
协议的修改还可以隐藏交换价格,以增加隐私假设。
为了执行保密的点对点交换,必须在保密代币上定义approve和transferFrom流程。
这些流程将由总共六个新函数管理:
有关这些函数使用的密码学的深入规范,请参阅原始的cWETH论文。
与常规的ERC-20批准逻辑相反,保密的批准会导致批准者的余额减少。这是因为在保密的transferFrom过程中,支出者无法验证批准者是否具有足够的余额,因为它是加密的。
此外,保密的批准操作需要提供operator地址,这是对通常的ERC-20 spender地址和allowance金额的补充。如果指定了operator地址,则spender无法调用confidentialTransferFrom来接收代币;只有operator有资格这样做。此约束对于保密的transferFrom的安全性和自定义至关重要,因为它使批准者可以指定智能合约作为operator来强制执行其他转移验证。
保密的批准给EOA的流程如下图所示:
一旦授予了allowance,spender就能够接收已批准的代币。下图说明了保密的transferFrom流程:
\
图2:保密的transferFrom流程1920×1405 176 KB
至关重要的是要理解,保密的approve和transferFrom操作于五个不同的加密金额:
在某些情况下,需要批准代币不是给具有加密密钥的EOA,而是直接给智能合约。由于智能合约不持有保密的私钥,因此它们无法解密保密的allowance值。此外,在这种情况下,批准者事先不知道接收者是谁,并且无法为特定的公钥加密该值。因此,任何用于智能合约的保密allowance都必须公开披露批准的金额。
下图描述了公开保密的批准流程:
\
图3:公开保密的批准流程3099×1750 379 KB
因为批准的金额是以明文指定的,所以必须完全且以原子方式使用公开保密的allowance,使其成为一次性批准。换句话说,如果未完全使用公开的allowance,则隐私假设要求将剩余值使用批准者的公钥重新加密,并在同一交易中添加回批准者的pending balance。这是因为对allowance值的公开更新将导致危及所转移金额的保密性。
下图描述了支出公开保密的allowance的流程:
\
图4:公开保密的transferFrom流程1920×681 118 KB
与常规保密的transferFrom的显着区别在于,allowance的剩余值将被加密并添加回批准者的pending balance,而不是驻留在专用的allowance存储中。
该协议还包括一种机制,供批准者取消保密的allowance,无论是作为加密的allowance授予给EOA,还是作为公开的allowance授予给合约。
下图显示了保密的allowance取消流程:
\
图5:取消 allowance 流程1920×563 100 KB
保密的allowance取消流程非常简单,因为所有加密的金额都保留在保密的approve和transferFrom操作中。所需的只是将它们添加回批准者的pending balance。
但是,公开的取消还需要ZK证明来验证allowance的剩余值已被加密。
为了使DEX正确运行,必须满足几个条件以保持交换过程的顺利和一致:
以下部分描述了由先前定义的保密allowance模型支持的保密点对点交换的执行流程。交换过程是交互式的,包括三个阶段:报价放置、报价接受和完成交换。
完整的交换流程如下图所示:
交换发起者公开定义和发布报价配置:汇率r(每assetSell的assetBuy)以及可用于交换的assetSell的最大金额M。
通过调用publicConfidentialApprove函数,将M个代币批准给指定的ZEX合约,可以保证用于交换的sell token的可用性。
在接受报价之前,交易对手必须首先验证特定报价的公开的allowance是否存在,以及报价是否尚未被接受。
然后,接受者选择在交换期间接收的assetSell的数量b(b \le M),并根据约定的汇率r计算向报价发起者支付的相应assetBuy金额a,取a=br。
之后,接受者必须通过confidentialApprove批准a个assetBuy代币,指定ZEX合约作为operator,报价发起者作为spender。此外,接受者还需要提供ZK证明,证明所选金额不超过发起者发布的assetSell的最大可用金额b。
为了完成交换,报价发起者必须首先验证交易对手的保密allowance是否足以支付特定报价。
之后,报价发起者需要计算要出售给报价接受者的assetSell的正确数量。这是通过在confidentialApprove期间解密提供的a来完成的,并计算出售金额b=a \over r。
然后,发起者准备转移b个assetSell代币,方法是使用接受者的公钥加密它们,并计算剩余的assetSell allowance l=M-b。
为了转移约定的assetSell金额,ZEX合约调用publicConfidentialTransferFrom,该函数将b个代币添加到接受者的余额中,而自我加密的allowance剩余金额l会添加回发起者的pending balance。最后,在同一交易中,发起者通过ZEX合约调用的confidentialTransferFrom,通过花费接受者在报价接受期间授予的保密allowance,以assetBuy接收付款a。
总而言之,用户要么完成交换并按照指定的汇率交换代币,要么随时取消批准以停止交换过程。DEX在任何时候都不会公开实际交换的金额,而只是公开地操作汇率和初始报价量的金额。
保密allowance数据存储在以下结构中:
struct ConfidentialAllowance {
address operator;
bytes amountEncryptionData;
bytes amountCommitmentData;
}
请注意,根据保密代币规范,加密和承诺数据会进一步解码。
Allowances存储在映射中:
mapping(address approver => mapping(address spender => ConfidentialAllowance));
授予给合约的保密allowance存储在映射中,其中批准的金额以明文提供:
mapping(address approver => mapping(address spender => uint256));
交换报价由以下结构定义:
struct Offer {
address initiator;
address acceptor;
address assetBuy;
address assetSell;
uint256 rate;
uint256 maxAmountToSell;
bytes amountToBuyEncryptionData;
bytes amountToBuyCommitmentData;
}
报价存储在一个简单的映射中:
mapping(uint256 offerId => Offer);
要授予给已注册EOA保密allowance,必须调用confidentialApprove函数:
function confidentialApprove(
address approver,
address spender,
address operator,
bytes calldata amountEncryptionData,
bytes calldata amountCommitmentData,
bytes calldata proofData
) external;
加密和承诺数据参数存储使用approver和spender的公钥加密的值,类似于cWETH协议中的transfer函数。
要授予给合约allowance,提供了publicConfidentialApprove函数:
function publicConfidentialApprove(
address approver,
address spender,
uint256 amount,
bytes calldata newBalanceEncryptionData,
bytes calldata amountCommitmentData,
bytes calldata proofData
) external;
此函数中的加密和承诺数据参数用于存储使用approver的公钥加密的新余额和金额值,以便在批准后更新余额。
要支出保密批准,operator必须调用以下函数:
function confidentialTransferFrom(
address approver,
address spender,
bytes calldata amountEncryptionData,
bytes calldata amountCommitmentData,
bytes calldata proofData
) external;
加密和承诺数据参数存储使用spender的公钥加密的转移金额,以及转移后剩余的使用approver的公钥加密的allowance金额。
要支出公开保密的allowance,spender合约将调用以下函数:
function publicConfidentialTransferFrom(
address approver,
address receiver,
bytes calldata amountEncryptionData,
bytes calldata amountCommitmentData,
bytes calldata proofData
) external;
加密和承诺数据参数包括使用接收者的公钥加密的转移金额,以及使用approver的公钥自我加密的剩余allowance金额。
要取消授予给EOA的保密allowance,approver必须使用以下函数:
function cancelConfidentialAllowance(
address approver,
address spender,
bytes calldata proofData
) external;
如果approver不等于msg.sender,则proofData包含ZK证明,以验证approver是否拥有私钥。
取消授予给合约的公开allowance必须通过以下函数完成:
function cancelPublicConfidentialAllowance(
address approver,
address spender,
bytes calldata balanceEncryptionData,
bytes calldata amountCommitmentData,
bytes calldata proofData
) external;
balanceEncryptionData用于存储退款后approver的新的DH加密的余额,而amountCommitmentData表示实际allowance退款金额的ElGamal承诺。
要创建交换报价,发起者需要调用以下函数:
function initiateOffer(
address assetBuy,
address assetSell,
uint256 rate,
uint256 maxAmountToSell,
bytes calldata approveData
) external returns (uint256 offerId);
approveData由在initiateOffer函数中调用的publicConfidentialApprove所需的参数和ZK证明组成。
要接受现有报价,提供了acceptOffer函数:
function acceptOffer(
uint256 offerId,
bytes calldata approveData,
bytes calldata proofData
) external;
approveData存储在acceptOffer函数中调用的confidentialApprove所需的数据。它还包括从发起者处购买的assetSell的加密金额。proofData表示ZK证明,证明该金额在报价的已定义最大可用金额范围内。
为了完成点对点保密交换,报价发起者需要调用以下函数:
function finalizeSwap(
uint256 offerId,
bytes calldata transferFromData
bytes calldata proofData
) external;
transferFromData由在交换完成期间调用的\newline publicConfidentialTransferFrom和confidentialTransferFrom函数所需的值组成。proofData参数是一个ZK证明,用于验证接受者的购买金额的正确解密和发起者的出售金额的计算。
本提案中概述的所有参数都旨在在链上可验证且与零知识电路兼容。
保密 approve 证明的电路信号列表如下:
公共信号:
私有信号:
运行这些信号,电路必须具有以下约束:
公开保密的 approve 证明的电路信号列表如下:
公共信号:
私有信号:
运行这些信号,电路必须具有以下约束:
用于支出保密allowance证明的电路信号列表如下:
公共信号:
私有信号:
运行这些信号,电路必须具有以下约束:
用于支出公开保密allowance证明的电路信号列表如下:
公共信号:
私有信号:
运行这些信号,电路必须具有以下约束:
用于取消保密allowance证明的电路信号列表如下:
公共信号:
私有信号:
运行这些信号,电路必须具有以下约束:
用于取消公开保密allowance证明的电路信号列表如下:
公共信号:
私有信号:
运行这些信号,电路必须具有以下约束:
用于接受交换报价证明的电路信号列表如下:
公共信号:
私有信号:
运行这些信号,电路必须具有以下约束:
用于完成交换报价证明的电路信号列表如下:
公共信号:
私有信号:
运行这些信号,电路必须具有以下约束:
必须强调ZEX协议的几个现有的安全挑战。
尽管本文概述了ZEX协议和保密allowance的主要功能概念,但仍有几个开放方向可供进一步研究。
首先,关于在交换报价期间管理要出售的最大可用金额,存在一个悬而未决的设计问题。在当前规范中,保证出售金额可用性的公共保密allowance只能使用一次。开放的问题是设计一种更强大的方法来动态更新公共allowance金额,从而提供实现多重填充报价的能力,而不会损害剩余allowance资金的保密性。
其次,当前的解决方案使用多个ZK证明来接受和完成报价,这会带来大量的gas开销。在执行报价操作时,必须在单个交易中验证多个证明。例如,在报价完成期间,必须根据提供的购买金额提供正确的出售金额计算的证明,以及publicConfidentialTransferFrom和confidentialTransferFrom函数调用的两个证明。尽管从与ZEX分离的代币批准模型使用的角度来看,这种方法似乎是一致的,但它大大增加了交换的总体成本。一种可能的补救措施是将证明聚合委托给受信任的协调器合约。但是,这会引入新的信任假设并扩大潜在的攻击面。
第三,可以扩展ZEX协议以隐藏初始报价的价格,最终提高交换的隐私性,但会迫使发起者和接受者进行议价。
- 原文链接: ethresear.ch/t/zex-v0-1-...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!