# Proofs of Custody - 托管证明

By [EthereumCN](https://paragraph.com/@ethereumcn) · 2021-10-18

---

来源：[https://dankradfeist.de/ethereum/2021/09/30/proofs-of-custody.html](https://dankradfeist.de/ethereum/2021/09/30/proofs-of-custody.html)

摘要：懒惰验证有利可图？托管证明是怎样的设计？如何有效防范懒惰验证？

感谢 Vitalik Buterin、Chih-Cheng Liang 和 Alex Stokes 富有助益的评论。

托管证明 (Proof of Custody) 是一种有助于解决“懒惰验证者“问题的构造。懒惰的验证者有这样的表现：他们不做他们应该做的工作，例如确保一些数据是可用的 (与数据分片有关) ，或一些执行是正确的 (用于执行链)——他们假装他们已经做了，并对结果签名，例如无论如何，证明都声称数据是可用的。

托管证明这个构造是一个改变博弈论的加密经济学基元，使懒惰验证不再是一个有吸引力的策略。

懒惰验证者的策略
--------

假设我们有一条运行良好的以太坊2.0链 (你可以代入你最喜欢的其他 PoS 区块链)。我们通常不期望坏事发生——出现数据被扣留，生成无效区块的情况。事实上，你可能甚至没看过这些情况的发生，因为只要系统由大多数的诚实验证者来运行，甚至没有必要试图以这些方式攻击它。因为这种攻击几乎可以确定会失败，这样做时没有意义的。

现在假设你运行一个验证者。这会有不同的成本——明显会有质押资金，但还有硬件成本、电力和网络宽带，这些都或直接 (你的供应商按每 GB 收费) 或间接 (当你的验证者在运行时，你的 netflix 播放会网速不够) 此需要支付。你能把开销压得越低，你就能从运行验证者获得越多的净收益。

在分片 Eth2 里你要做的其中一个任务是，保证分片数据的可用性。每个证明委员会都会分到一个 blob 的数据需要做验证，大小大约是 512kB 到 1 MB。每个验证者的任务就是下载它并存储 90 天左右。

但是，如果你只是简单地对分片数据的全部证明签名，而不是真的下载那些数据，会发生什么？你还会获得全部的奖励，但你的成本会突然减少了。我们假设网络处于良好状态，这样你的懒惰不会马上对网络造成什么影响。假设你运行验证者的收益是每投一次票获得 1 美元，而每年下载所有区块的开销是 0.10 美元。现在，你的收益就增加到 1.1 美元。

![](https://storage.googleapis.com/papyrus_images/d148d3eed0969cc5b95f22340497474c3555d21331d6b3c2133c491bdfedbbe5.png)

这个问题被称为验证者困境，并由 Luu 等人在论文《解密共识计算机中的激励机制 ([Demystifying Incentives in the Consensus Computer](https://eprint.iacr.org/2015/702.pdf))》中提出。

### 但我决不会这样做！谁会这样作弊啊？

在我们看来，在这样的博弈中，你肯定不会去做贿赂这样的事，而是保持诚实履行职责。但事情往往比这更微妙。

让我们假设，在运行了验证者多年后，有一个新客户端出现了，并声称其成本效益提高了 10%。人们运行它，发现它真的有效，而且似乎也是安全的。而它实际做到这一点的方法就是不下载分片区块。

这甚至可能是意外发生的。有人在开发过程中偷工减料，一切看起来都很正常，它只是没有加入正确的分片子网且没有人在意这点，因为它不会在正常运行中造成任何故障。

有些人可能会运行这个客户端。

其他可能发生的事情是，会出现帮你下载的服务。每个分片数据 0.01 美元，他们会下载那些数据，存储 90 天，然后给你发送信息说数据可用，你可以对证明签名了。这种情况有多坏？

这相当糟糕。因为随着很多人开始使用这项服务时，它就成了一个单点故障。或更糟糕的是，它可能成为攻击的一部分。如果它能让超过 50% 的验证者对一个分片数据的可用性投票，而不发布该数据，这将构成一次扣留攻击 (withholding attack)。

如通常情况一样，不诚实行为可以有很多伪装，因此我们最好的措施是在使诚实的策略是理性的，从而达到平衡。

托管证明与新的博弈
---------

托管证明的工作原理是这样的：想象一下，我们可以在一个分片数据里放入一个“炸弹”——如果你对这个数据签名，你会遭受很严重的惩罚 (你会被罚没)，3000 美元。这样，你肯定不会想对这个数据签名。

那这会让你想下载数据吗？这肯定是避免对炸弹签名的一个方法。但是，如果任何人都能检测到这个炸弹，然后有人就可以简单地写这样一个服务：如果它是一个炸弹的话，在你对证明签名前警告你。因此，炸弹需要是针对某个个人验证者，且没有其他人可以计算出这个分片数据是否是一个炸弹。

好了，现在我们有了托管证明的基本素材了。我们需要：

1.  一个临时秘密 (ephermeral secret)，每个托管周期 (约 90 天) 后都要对其重新计算，对每个验证者来说都是独立的，然后在过期后再披露 (这样其他验证者就有机会检查托管证明了)
    
2.  一个函数，它获取整个分片 blob 数据还有临时密钥 (ephemeral key)，输出是 0 (表示不是炸弹)，或以极小的概率输出 1 (表示这个 blob 是炸弹)
    

这里的关键是，临时秘密是不能让其他人知道的，因此会有三个罚没条件：

1.  如果任何人知道了当前的临时秘密，该验证者会被罚没
    
2.  临时秘密必须在托管周期结束后公布，没有做到这点也会被罚没
    
3.  对炸弹签名会导致罚没
    

我们如何创建这个函数？一个简单的构造会这样运作：计算一个默克尔树的叶子节点 `(data0, secret, data1, secret, data2, secret, ...)` ，如下所示：

![](https://storage.googleapis.com/papyrus_images/5793a6ef8220c5f0af41b2f9e14f974040eba0099549297c18592a56c75b4b1f.png)

然后把前 10 位输入到逻辑函数 `AND`。然后它会给你一个比特，在预期的 1024 次中有 1 次是 1。

如果不知道秘密和数据，就无法计算出这个函数的结果。

（因为我们确实想实现在验证者间共享秘密，所以在优化这个函数方面已经做了大量的工作，以便它可以在 MPC (多方计算) 中进行有效计算，而默克尔树则不能。因此，我们建议采用基于通用哈希函数和勒让德 (Legendre) 符号的结构：[https://ethresear.ch/t/using-the-legendre-symbol-as-a-prf-for-the-proof-of-custody/5169](https://ethresear.ch/t/using-the-legendre-symbol-as-a-prf-for-the-proof-of-custody/5169))

### 新的博弈

好了，现在有了托管证明，任何分片数据都有 1/1024 的机会是炸弹，不下载它你就不知道哪个是。

当数据不是炸弹时，懒惰的验证者不会有什么问题。但是，当它是炸弹时，我们会看到巨大的差异：诚实验证者只会跳过这个证明，因为它影响很小，只是将收益设为 0。但是，懒惰的验证者对它签名就会被罚没，造成巨大损失。现在的收益矩阵看起来是这样的：

![](https://storage.googleapis.com/papyrus_images/b20ce9591328d7215dbdc2f4163a6ddc8045c741a3a965b8a6780e9192b4af97.png)

在第三栏，我们看到懒惰验证者的预期收益现在是负数。由于懒惰的所有原因是通过减低成本来增加收益，这意味着懒惰验证者现在不再是一个吸引人的策略。

用于执行的托管证明
---------

验证者的另一个任务是验证区块的正确执行。这意味着需要验证新的状态根，它是应用所有事务后验证区块是否正确的一部分。托管证明这个想法还能应用到这种情况：验证者将不需以上述同样的方式计算托管证明，但是数据是_执行痕迹_。执行痕迹是由一步步区块执行生成的一些输出。它在任何意义上都不需要是完整的；我们只想要它的两个特性：

1.  在没有实际执行区块的情况下应该是难以猜到执行痕迹的。
    
2.  执行痕迹的总大小应该足够大，以至于简单地将其累加到正常区块上是不理想的。
    

要这样做还有一些简单的选项；例如，简单地输出 EVM 执行的每一单条指令字节，可能会导致每个执行区块有几 MB 的执行痕迹。另一个选择是使用栈顶。

### 有了欺诈证明，执行上我们还需要托管证明吗？

当我们把执行链升级到无状态，这意味着区块验证可以不用到当前的状态，欺诈证明变得很容易。（如果没有无状态，就很难：欺诈证明总是必须被打包到不同于欺诈所发生的链，因此当欺诈证明必须被验证时，实际的前状态将不可用了。）

这意味着，如果一个验证者出了一个无效执行区块，他有可能会被罚没。此外，我们还可以惩罚任何对此区块做过证明投票的验证者。这是否意味着不再需要监护证明呢？

它肯定会改变双方的权衡。但即使有了这项惩罚，懒惰验证仍然是一个理性策略。对于验证者来说，简单地对每个区块签名而不验证不是一个好主意，因为攻击者只需牺牲他们自己一个验证者，你就会遭受罚没。

但是，你可以采用以下策略：在每个新区块上，在你自己签名前，等一小部分其他验证者先对它签名。那些最先对它签名的不太可能是懒惰的验证者，因为他们会采用相同的策略。在大多数情况下，这将给你带来相当好的保护，但在系统层面上，区块链仍然会在一些极端情况下容易遭到攻击。

欺诈证明的情况因此得到了改善，但托管证明对于确保懒惰验证不能成为一个理性策略来说仍然更胜一筹。

它与数据可用性检查有何不同？
--------------

我写过一篇关于数据可用性检查的[入门文章](https://www.ethereum.cn/Eth2/data-availability-checks)。用于分片数据的托管证明似乎尝试解决一个非常相似的问题：确保提交到分片 blob 头的数据在网络上是确实可用的。

所以我们可能会想知道：我们是否同时需要托管证明和数据可用性检查？

不过，这两种构造之间有一个重要区别：

*   数据可用性检查确保数据可用性独立于诚实大多数的假设。即使是一个控制了全部押金的强大攻击者也无法骗过所有节点，让它们接受实际上被扣留的数据是可用的。
    
*   相比之下，如果大多数的权益都在进行攻击的话，监护证明并没有帮助。攻击的大多数可以计算出监护证明，而无需向任何人披露该数据。
    
*     
    

因此，从理论上讲，数据可用性检查严格来说是优于分片数据的托管证明的：它们是无条件成立的，而后者只是为了让理性的验证者保持诚实，是攻击事件的发生几率更低。

为什么我们仍然需要用于分片数据的监护证明呢？它可能不一定需要。然而，在数据可用性检查方面存在一些实际问题，使得它需要一个防止丢失数据的“第一道防线”：

其原因是，数据可用性检查的工作原理是将不可用的区块通过分叉选择规则中排除出去。但是，这不可能是永久性的：数据可用性检查只能确保最终，每个人都会看到相同的结果，但不是即时的。

这样做的原因是，发布一个部分可用的区块，可能会导致有些节点以为它是可用的 (他们看到所有的样本)，而其他一些节点认为它是不可用的 (缺乏一些样本)。数据可用性检查确保在这些情况下，数据总是可以被重构的。然而，这需要一些节点首先获得足够的样本来重构数据， 然后重新播种样本，这样每个人都可以看到；这个过程需要几个 slot。

在这个构造中，监护证明和数据可用性检查有两个正交功能：

1.  用于分片数据的监护证明确保了诚实的大多数验证将只会构建一条链，其中所有的分片数据都是可用的，并会稳妥地播种到各个委员会。一个少数验证者构成的攻击不能轻易造成破坏。
    
2.  数据可用性检查将保证，即使占大多数押金的验证者参与攻击，它们也不能迫使剩余的全节点认为有扣留数据的区块链是被最终敲定的。
    

* * *

_ECN的翻译工作旨在为中国以太坊社区传递优质资讯和学习资源，文章版权归原作者所有，转载须注明原文出处。另，ECN 的编译内容均不构成投资建议。_

---

*Originally published on [EthereumCN](https://paragraph.com/@ethereumcn/proofs-of-custody)*
