更安全的CEX:偿付能力证明

1. 引言

以密码学技术(如zk-SNARKs),而不是依赖于政府许可证、审计、审查创始人等官方手段,来证明某中心化交易所在链上有足够的资产来覆盖其用户债务——Proof-of-Solvency(偿付能力证明)。

甚至,交易所可构建一个系统,在未经储户同意的情况下,其根本无法提取储户的资金。从而可探索从“don’t be evil”的有抱负的好人CEX 到 “can’t be evil”的整个光谱,但这对于链上DEX来说,存在inefficient和隐私泄露的问题。

2. Balance lists和Merkle树:old-school 偿付能力证明

交易所尝试借助密码学来证明其未欺骗用户的努力由来已久:

若:

  • 证明客户存款等于X——即“proof of liabilities”(债务证明)
  • 证明拥有X coins的私钥——即“proof of assets”(资产证明)

则拥有了“proof of solvency”(偿付能力证明):即证明交易所有资金来偿付客户存款。或称为"proof of reserve"(储量证明)。

2.1 “proof of liabilities”(债务证明)

证明存款最简单的方式是发布a list of (username, balance) pairs。每个用户可检查其balance是否在该list内,任何人可检查the full list:

  • 1)检查每个balance都是非负数的;
  • 2)检查所有balance总和 等于 声称总额。

当然,未避免隐私泄露,可对以上方案稍作修改:

  • 发布a list of (hash(username, salt), balance) pairs,然后给每个用户私下发送其salt值。

2.1.1 “proof of liabilities”(债务证明)——Merkle sum tree

但是,上述方案仍会泄露balance,同时会泄露balance的变化。
为解决隐私问题,2014年Bitcoin讨论The Merkle approach to proving liabilities 和 2015年Bitcoin讨论Is there a generally agreed on protocol for creating proof of solvency?中,引入了:

  • Merkle tree技术

Merkle tree技术包含了:

  • 将the table of customers’ balances放入类似如下的Merkle sum tree中:
    在这里插入图片描述
    在Merkle sum tree中,每个节点都为a (balance, hash) pair。最底层的叶子节点代表了各个单独客户的balance及其salted username hashes。在每个更高层节点中,其balance为底层2个节点的balance之和,hash为底层2个节点的哈希值。而Merkle sum proof与Merkle proof类似,为a “branch” of the tree,包含了由该叶子节点到根节点的所有姐妹节点。

交易所将给每个用户发送其balance的Merkle sum proof,然后用户就相当于得到了 其balance被正确包含在total中的 保证。
一个简单的代码示例见:https://github.com/ethereum/research/blob/master/proof_of_solvency/merkle_sum_tree.py

# The function for computing a parent node given two child nodes
def combine_tree_nodes(L, R):
    L_hash, L_balance = L
    R_hash, R_balance = R
    assert L_balance >= 0 and R_balance >= 0
    new_node_hash = hash(
        L_hash + L_balance.to_bytes(32, 'big') +
        R_hash + R_balance.to_bytes(32, 'big')
    )
    return (new_node_hash, L_balance + R_balance)

# Builds a full Merkle tree. Stored in flattened form where
# node i is the parent of nodes 2i and 2i+1
def build_merkle_sum_tree(user_table: "List[(username, salt, balance)]"):
    tree_size = get_next_power_of_2(len(user_table))
    tree = (
        [None] * tree_size +
        [userdata_to_leaf(*user) for user in user_table] +
        [EMPTY_LEAF for _ in range(tree_size - len(user_table))]
    )
    for i in range(tree_size - 1, 0, -1):
        tree[i] = combine_tree_nodes(tree[i*2], tree[i*2+1])
    return tree

# Root of a tree is stored at index 1 in the flattened form
def get_root(tree):
    return tree[1]

# Gets a proof for a node at a particular index
def get_proof(tree, index):
    branch_length = log2(len(tree)) - 1
    # ^ = bitwise xor, x ^ 1 = sister node of x
    index_in_tree = index + len(tree) // 2
    return [tree[(index_in_tree // 2**i) ^ 1] for i in range(branch_length)]

# Verifies a proof (duh)
def verify_proof(username, salt, balance, index, user_table_size, root, proof):
    leaf = userdata_to_leaf(username, salt, balance)
    branch_length = log2(get_next_power_of_2(user_table_size)) - 1
    for i in range(branch_length):
        if index & (2**i):
            leaf = combine_tree_nodes(proof[i], leaf)
        else:
            leaf = combine_tree_nodes(leaf, proof[i])
    return leaf == root

这种设计方案要比fully public list的隐私泄露要少,同时,可在每次发布root时对branches进行shuffling 来进一步降低隐私泄露,但一定程度的隐私泄露仍然存在,如:

  • Chalie知道某人有164 ETH,某2人的balance之和为70ETH等。

控制多个账号的攻击者,可能可获得交易所相当数量客户的资金量。
上述方案的一个重要的微妙之处在于:

  • 可能存在负数balance的情况:
    如交易所的客户balance为1390 ETH但实际账上仅有890 ETH,若在树中插入一个balance为-500 ETH的fake账号?
    不过这种概率并不会破坏整个方案,原因在于此处设计的是Merkle sum tree,而不是常规的Merkle tree。假设Henry为交易所控制的fake账户,然后交易所试图在树中插入-500 ETH:
    在这里插入图片描述
    Greta的证明验证将失败:因交易所在其证明中包含了Henry的-500 ETH节点,该节点无效Greta可拒绝。而Fred和Eve的证明验证也将失败,因其证明中包含了Henry之上的-230 ETH中间节点,因此也是无效的。为此,为作弊成功,交易所需寄希望于整棵树的右半段没有任何一个人取检查其balance proof。
    若交易所可识别出具有500ETH的用户不去校验其balance proof,或者,不会抱怨其从未收到过相应的balance proof,则交易所可作弊成功。但是,交易所也可直接将这些用户剔除出树,也具有相同的效果。
    因此,若仅是要实现“proof of liabilities”(债务证明),以上Merkle sum tree方案就足够了。

但是,以上Merkle sum tree方案的隐私属性仍不够理想,若以更巧妙的方式来使用Merkle tree,如https://github.com/ethereum/research/blob/master/proof_of_solvency/crazy_merkle_tree.py中“make each satoshi or wei a seperate leaf”,隐私效果将得到改进。但最终,借助更现代的技术,可更好的解决隐私问题。

2.1.2 借助zk-SNARKs来提升隐私和强健性

zk-SNARKs之于密码学 类似于 transformers之于AI:为强大的通用技术,将为几十年前的一系列问题提供一整套特定于应用程序的技术。
借助zk-SNARKs,可大幅简化和改进“proof of liabilities”(债务证明)中的隐私问题。

最简单的方式是:

  • 1)将所有的用户存款放入一棵Merkle树中(或,更简单,采用KZG多项式承诺
  • 2)使用zk-SNARK来证明该树中的所有balance为非负数的,且总额为某声称的值。
  • 3)若添加一层hashing for privacy,则给每个用户的Merkle branch(或KZG证明)将不会泄露任何其它用户的balance信息。

在这里插入图片描述
【其中的Q多项式成立在于:“针对multiple points时,可将evaluations of a polynomial f f f on a set S ⊂ F S\subset \mathbb{F} SF 看成是 given as a polynomial r ∈ F < ∣ S ∣ [ X ] r\in\mathbb{F}_{<|S|}[X] rF<S[X] with r ( z ) = f ( z ) r(z)=f(z) r(z)=f(z) for each z ∈ S z\in S zS。此时: r ( z ) = f ( z ) r(z)=f(z) r(z)=f(z) for each z ∈ S z\in S zS,等价为, f ( X ) − r ( X ) f(X)-r(X) f(X)r(X) 可被 Z S ( X ) Z_S(X) ZS(X)整除,其中 Z S ( X ) = ∏ z ∈ S ( X − z ) Z_S(X)=\prod_{z\in S}(X-z) ZS(X)=zS(Xz)”,详细参看Efficient polynomial commitment schemes for multiple points and polynomials学习笔记的“2.3 Polynomial commitment scheme”。】
使用KZG承诺是避免隐私泄露的一种方式,因其不再需要在证明中提供“姐妹节点”;且一种简单的zk-SNARK可用于证明balance之和以及每个blance为非负数。

为证明balance总和以及每个balance为非负数,可在KZG的基础上,采用一种特殊用途的zk-SNARK,如:

  • 引入辅助多项式 I ( x ) I(x) I(x),可“builds up the bits” of each balance。如,假设balance值小于 2 15 2^{15} 215,且每16个位置tracks a running total with an offset so that it sums to zero only if the actual total matches the declared total。若 z z z为某order-128 root of unity,设计的balance I ( X ) I(X) I(X)多项式中:
    • 1)以16bit来表示balance总和以及每个balance为非负数。
    • 2)前15个bit为balance的二进制形式表示的约束:第1个值为balance二进制形式的最高1位;第2个值为balance二进制形式的最高2位;第3个值为balance二进制形式的最高3位;以此类推,第15个值即为balance值。以等式表示为:
      若  i m o d    16 ∉ { 0 , 15 } ,有  I ( z i ) − 2 ∗ I ( z i − 1 ) ∈ { 0 , 1 } 若\ i\mod 16 \notin \{0,15\},有\ I(z^i)-2*I(z^{i-1})\in\{0,1\}  imod16/{0,15},有 I(zi)2I(zi1){0,1}
      P ( x ) P(x) P(x)关联匹配的约束关系为: I ( z 16 x + 14 ) = P ( w 2 x + 1 ) I(z^{16x+14})=P(w^{2x+1}) I(z16x+14)=P(w2x+1)
      balance为非负数,即相应二进制最高位应为0,对应约束表示为: I ( z 16 x ) = 0 I(z^{16x})=0 I(z16x)=0
    • 3)balance总和约束,通过最后一个bit来体现,令用户balance均值 = 声称balance总和/用户数,有 前m个用户的balance - m * 用户balance均值m = 总用户数时,前m个用户的balance - m * 用户balance均值结果为0,具体约束表示为: I ( z 16 x + 15 ) = I ( z 16 x − 1 ) + I ( z 16 x + 14 ) − the declared total user count I(z^{16x+15})=I(z^{16x-1})+I(z^{16x+14})-\frac{\text{the declared total}}{\text{user count}} I(z16x+15)=I(z16x1)+I(z16x+14)user countthe declared total,其中 the declared total \text{the declared total} the declared total为该Merkle树中所有用户balance总和(如本例中为1480),而 user count \text{user count} user count为该Merkle树中的总用户数(如本例中为8)。【此处, I ( z 127 ) = I ( z − 1 ) = 0 I(z^{127})=I(z^{-1})=0 I(z127)=I(z1)=0。】

本例中, I ( x ) I(x) I(x)的有效值设置可为:0 0 0 0 0 0 0 0 0 0 1 2 5 10 20 -165 0 0 0 0 0 0 0 0 0 1 3 6 12 25 50 -300……

可将以上方程式转换为多项式表示,然后使用zk-SNARKs来证明。这并不是最优协议,但可充分说明借助这样的密码学证明可解决实际问题。

再额外引入少量方程式,以上类似的约束系统可调整为适合更复杂的场景。如,在杠杆交易系统中,允许单个用户具有negative balance,但其必须有足够的抵押保证金。SNARK可用于证明更复杂的约束,向用户保证,交易所不会通过秘密豁免其他用户不遵守规则来冒资金风险。

未来,这种“ZK proof of liabilities”(债务ZK证明)不仅可用于交易所用户存款,也可用于更广泛的贷款。任何人借贷时可向包含该贷款的 tree或多项式 中插入一条record,该结构的root将公开上链。使得任何寻求贷款的人 都可向 出借人ZK-prove其未贷出过多的款。最终,法律创新甚至可以使以这种方式承诺的贷款 比 没有承诺的贷款 具有更高的优先级。详细可查看2022年5月微软研究中心、Flashbots以及以太坊基金会联合发表的论文Decentralized Society: Finding Web3’s Soul:通过某种形式的“soulbound tokens”在链上产生负面声誉或债务负担的一般概念。

3. “proof of assets”(资产证明)

资产证明的最简单方式为:

  • 为证明你拥有X coins,可在某个预先商定时间 或 某笔包含了特定备注“these funds belong to Binance”的交易内 转移X个coins。

未避免支付交易手续费,可转为对某off-chain message进行签名。目前:

这种直接转账的资产证明方式,虽然简单,但存在2个实际问题:

  • 1)Dealing with cold storage:需处理冷存储
  • 2)Collateral dual-use:担保双重用途

3.1 “proof of assets”(资产证明)——冷存储

安全考虑,大多数交易所的大多数客户资金都在“cold storage”中:

  • 在offline计算机中签署交易,需手工移到网络上。

cold storage通常是空气隔离的:如某cold storage setup中包含了一台永久离线的电脑,该电脑负责为已签名交易生成QR码,然后使用手机可扫描该QR码。
而现代交易所协议更疯狂,通常包含多个设备见的多方安全计算。
考虑到这种设置,即使是一条额外的消息来证明对某地址的控制也是一项昂贵的操作!

交易所的解决方案可有:

  • 1)维护少量公开长期使用的地址:交易所生成少量地址,为每个地址发布ownership证明,然后重复使用这些地址。这是最简单的方案,但却存在如何保证安全性和隐私性的问题。
  • 2)有多个地址,随机证明其中的一小部分:交易所可有多个地址,可能每个地址仅使用一次,在某笔交易之后就不再使用。此时,交易所可能有一个协议,其中不时会随机选择一些地址,并且必须“打开”以证明所有权。某些交易所已与auditor一起采用了类似的方式,但原则上该技术可以完全自动化的流程实现。
  • 3)更复杂的ZKP方案:如,交易所设置其所有地址为1-of-2 multisigs:
    • 每个地址的其中一个密钥为独有的,不会在其它地址中使用;
    • 每个地址的另一个密钥为以某种复杂但非常高安全性的方式存储的一些“大”紧急备份密钥的blinded版,如某12-of-16 multisig。为保护隐私和避免泄露整个地址集,借助这种方式,交易所甚至可在链上运行ZKP来证明其链上所有地址的total balance。

3.2 “proof of assets”(资产证明)——担保双重用途

在彼此之间来回交换抵押品以证明准备金,这是交易所很容易做到的事情,并允许它们在实际上没有偿付能力时假装有偿付能力。

理想情况下,“proof of solvency”(偿付能力证明)应实时完成,且每个区块都更新相应的证明。若这实际不可实现,则可在不同交易所间以固定的时间表来证明reserves(储量)——如每周二的1400 UTC时。

3.3 对法币的“proof of assets”(资产证明)

交易所不只持有加密货币,在银行系统中还持有法币。如需对法币进行资产证明,将不可避免的依赖“fiat(法定)”信任模式:银行自身可证明balance,审计员可证明资产负债表等。
鉴于法币是不可加密验证的,这是在该框架内可以做到的最好的,但这仍然值得做。

另一种方法是将一个运营交易所并处理资产支持稳定币(如USDC)的实体与另一个实体(USDC本身)彻底分开,后者负责加密货币和传统银行系统之间的现金流入和流出流程。因为USDC的“负债”只是链上ERC20代币,所以负债证明是“免费”的,只需要资产证明。

4. Plasma和validiums:能否让CEX为non-custodial?

进一步设想:我们不仅想要证明交易所有资金来偿付用户,而是,想要“完全阻止交易所窃取用户的资金”。
为实现以上设想:

  • 1)方案一是Plasma:为以太坊2017~2018受欢迎的扩容方案。Plasma会将balance切分为一组独立的“coins”,每个coin分配有index 并 存在与某Plasma区块Merkle tree的特定位置。某coin的有效转账为将交易插入某tree的正确位置,该tree的root会发布到链上。
    在这里插入图片描述
    OmiseGo试图基于Plasma协议构建一个去中心化交易所,但是他们转向了其它想法——Plasma Group自身,也是Optimism(为optimistic EVM rollup项目)

2018年设想的Plasma的技术局限性(例如,证明硬币碎片整理)不值得视为关于整个概念的某种道德故事。自2018年Plasma讨论达到顶峰以来,ZK-SNARKs在扩容相关用例方面变得更加可行,正如我们上文所述,ZK-SNARKs改变了一切。

Plasma思想的更现代版本是Starkware的Validium:与ZK-rollup基本一致,不同之处在于,Validium的数据是维护在链下的。Validium可用于很多场景,如某中心化服务器需运行某代码,并证明其代码执行正确。借助Validium,运营商无法窃取资金,但根据实施的细节,如果运营商消失,一些用户资金可能会被卡住。

由CEX到DEX,是存在中间地带的,包括各种形式的混合中心化,可以获得一些好处,如效率,但仍有许多密码护栏,防止中心化运营商参与大多数形式的滥用。
在这里插入图片描述
但值得关注的是这个设计空间右半部分的基本问题:处理用户错误。到目前为止,最重要的错误类型是:如果用户忘记了密码、丢失了设备、被黑客入侵或以其他方式无法访问其帐户,该怎么办?

交易所可解决该问题:首先使用邮箱恢复,若邮箱恢复失败,可采用更复杂的KYC机制。为解决这类问题,交易所需实际能控制这些coins。以能恢复用户账号资金为名,交易所也有能力将其用于窃取用户账号资金。这是不可避免的取舍。

理想的长期解决方案为:让交易所用户self-custody(自我托管),并辅用多签钱包和social recovery wallets技术,帮助用户处理紧急情况。但长期来说,有2种明确的选择:
在这里插入图片描述

5. 结论:展望更好的交易所

短期来说,有2种类型的交易所:

  • custodial交易所
  • non-custodial交易所:当前为类似Uniswap这样的DEX,未来可能是被密码学“约束”的CEX——其用户资金存储在类似某validium智能合约中。未来也可能有half-custodial交易所,信任其法币而不是加密货币。

这2种类型的交易所将长期存在,为改进custodial交易所的安全性,可为其添加"proof of reserve"(储量证明)——包括“proof of asset”(资产证明)和"proof of liabilities"(债务证明)。在为两者制定好协议方面存在技术挑战,但我们可以而且应该尽可能在这两方面取得进展,并尽可能开源软件和流程,以便所有交易所都能受益。

从长远来看,我希望我们越来越接近所有非托管交易所,至少在加密方面如此。钱包恢复将存在,可能需要为处理小额交易的新用户以及出于法律原因需要此类安排的机构提供高度集中的恢复选项,但这可以在钱包层而不是在交易所本身完成。magic.linkPolymarket等平台交互的方式就是这种方法的一个例子。在法定货币方面,传统银行系统和加密生态系统之间的移动可以通过资产支持稳定币(如USDC)的现金流入/现金流出流程来实现。然而,我们还需要一段时间才能完全到达那里。

参考资料

[1] Having a safe CEX: proof of solvency and beyond
[2] V神提安全的CEX偿付能力证明 盼交易所变非托管防止挪用

附录A magic.link与Polymarket

magic.link为深受Web3开拓者信赖的、无摩擦的、安全的、non-custodial的instant Web3钱包:

  • 无需下载
  • 无需密码
  • 无seed phrase

在这里插入图片描述
Polymarket为基于Polygon链构建的信息交易平台,当前支持的连接方式有2种:

  • 1)使用magic.link,以passwordless email方式登录;
  • 2)使用metamask
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值