当我们把比特币存入一个平台(包括比特币交易所,off-chain 钱包等,但是不包括 on-chain 钱包,因为 on-chain 的钱包其实是我们自己握有自己的币,平台没有能力挪用)以后,一个担心就有了,这个平台会不会挪用我们储户的币去做一些有风险的事情呢?所以需要有一种方式可以证明平台手里持有的币不少于所有用户存入的币,这个就是所谓的百分百准备金证明了。比如币付宝的网站上就有一篇博客 http://blog.bifubao.com/2014/03/16/proof-of-reserves/ 来描述他们是如何进行证明的,乍一看上去不是太好理解,所以本文中来给大家做一个由简入繁的讲解,希望成为一块垫脚石。本文是基础篇,后面还会有进阶内容。
列出所有账目明细即可证明
如果不考虑隐私问题,这个证明就太简单了。平台公布他们自己的钱包地址,这样我们每个人都可以到 blockchain.info 上查询到他们的资产总额了。例如我们可以通过币付宝公布的地址来查看一下他们手里到底有多少个币。然后,再把所有用户的账号和余额也都列出来,公布到网上。大家上去看看自己的账号上的余额对不对,这样只要有个别的储户看到自己的余额有问题,就可以说明平台露馅了。
那么平台有没有可能通过造假来实现挪用资金而不被发现呢?答案是,只要有大量的用户都时不时的来查对自己的余额,那么造假的可能性是没有的。试想一种最极端的情况,有几个储户是机构的自己人,他们是可能说谎的。但是其实他们说谎也没有什么意义:把自己的余额往多里说,那么最终总账上的钱就不够数了,这不是自己给自己找麻烦吗?往少处说倒是可以,但是就更没有意义了。总之,这种方法从逻辑上是可以证明准备金率是百分百的。
使用哈希是为了隐私保护
这种”无隐私“的证明方法,实际中是不能用的,但实际中的证明机制的确实也是基于这个逻辑。只不过是在此之上又用了哈希以及 Merkle Tree 这样的数学方法来进行了对储户和机构的隐私保护。来一起看一下,哪些隐私,如何保护?
先来保护用户的隐私,主要就是要把账号隐藏起来。如何做到呢?其实就是不发布账号了改为发布对应的一个哈希值。运算哈希值的方式并不唯一,本文中选择一种最简单的方式。把账号和余额拼接成一个字符串,然后对它运算哈希。所以,假如我的账号是 happypeter@example.com,账户余额 3.12 个比特币,选用的哈希算法是 sha256,那么最终可以这样来运算我的哈希值:
hash = sha256('happypeter@example.com3.12')
实际中,我可以在我自己的苹果机器上打开命令行,然后执行:
>>> hashlib.sha256('happypeter@example.com3.12').hexdigest()
'4986c466a6218dba6eb8ca6f31d2eb630b7df59c6ed7a7484db58b5a00064612'
大家如果用的不是苹果的机器,也可以请教身边的人如何来进行这个操作。总之,任何人都可以在任何机器上进行相同的 sha256 运算,而且对于固定的输入,输出也是永远一样的。这样平台发布了我的账户的哈希之后,我就可以对比我自己的运算结果,运算结果相等,就意味着平台没有对我的余额撒谎。这样既可以验证,因为不同的输入内容不可能得到相同的哈希,同时也不会暴漏我的隐私,其他用户看到我的哈希也不可能推算出账号,因为哈希是个”单向算法“。更多关于哈希的知识,参考我前面的一期《什么是哈希》。
最终平台会发布一个 Merkle Tree
下面该说平台了。首先必须要公开的就是平台的的总账户余额,这个是一切一切的基础,不能当做隐私保护起来。可以保护的就是平台的用户数量。所以实际中平台发布信息的时候,不会把所有的用户的哈希都展示出来。而是搭建出一个 Merkle Tree,这样平台只需要公布 Merkle Tree 上的一小部分节点的信息,就可以逻辑完备的证明百分百准备金了。
先来说说构建过程。
在最底层,就是前面我们说的所有用户的哈希。向上走,父节点余额等于左节点余额加上右节点的余额
parent.sum = left.sum + right.sum
父节点的哈希这样算: 父节点余额,左边的哈希,右边的哈希拼成一个字符串,然后对这个字符串运算哈希:
parent.hash = sha256( concat( parent.sum, left.hash, right.hash ))
举个例子,如果左节点的余额是 36,哈希是 bbbb(只是举个例子,实际中的哈希肯定看起来更随机),右边节点的余额 32,哈希是 aaaa,那么运算“父哈希”的过程就是这样:
parent.hash = sha256('68bbbbaaaa')
这样平台可以一路算到 Merkle root。这棵树最终算出来之后,如果我想要来进行验证,平台就只需要公开我自己的 hash,以及通过我自己的哈希能够向上一路推导到 Merkle root 的所有的相关节点的信息就可以了,这样平台总的用户数就被隐藏了。如果我登陆到我自己的币付宝账户,就可以在 https://www.bifubao.com/tree 看到这样的一个部分树。
当然有心的用户还是可以通过 Merkle tree 的高度来推算大概的平台用户数,但是这只是因为我们运算中采用的是平衡结构的树,如果我们用非平衡树的形式来构建 Merkle Tree 那就解决了这个问题。
好,这里大家了解了一个简化版的 Merkle Tree 验证方法的基本逻辑,下一篇跟大家一起分析一下这样的做法为啥说是具有“逻辑完备性”的。之后,会继续讨论这种简化版本的模式有什么不足的地方,需要添加哪些新的细节进来进行完善。