本文提出了一种新的比特币隐私方案,该方案旨在避免地址复用带来的隐私问题,同时保持地址复用的一些便利性,并确保仅通过比特币时间链即可恢复钱包,且避免了可见的指纹。该方案通过引入一种通知交易和共享密钥机制来实现,并在发送者和接收者之间建立一种关系,以便后续的交易可以安全地进行。
作者:Kixunil
来源: https://gist.github.com/Kixunil/0ddb3a9cdec33342b97431e438252c0a
本文提出了一种新方案,既能避免地址复用,又能保留地址复用的一些便利,还能保证只需比特币时间链即可复原钱包,而且避免了可见的指纹。本方案的平均开销可以忽略不计。
地址复用(address reuse,重复使用同一个地址)是最破环隐私性的习惯之一。但是,不能否认,地址复用确实很方便,要不然人们也不会这么做。在长期的商务关系中尤其如此,它避免了来回传递新地址的需要。
这个问题现有的解决方案包括:
本文希望能解决 BIP47 的 体积/痕迹 问题,同时保证只需助记词就能恢复钱包,无需对手方在线配合。
类似于 BIP47,本方案也要使用 “通知交易(notification transaction)”。不过,跟 BIP47 不同的是,我们这里的通知交易同时也是一笔 “真实的” 交易。它是建立商业关系的双方在首次使用本方案时要执行的交易。通知交易的发送 必须 花费下列某种类型的至少一个输入:
发送者 必须 能够用 Taproot 地址来收款。接收方也 必须 使用 Taproot 地址来收款。(理论上也可以使用 P2PK,但这是很罕见的,所以会更显眼。)交易的双方 可以 使用 PayJoin 但 不能 让第三方加入。
在使用这种方案时,发送者 必须 用下列算法生成一个找零输出。
p_sender
。P_receiver
。shared_secret = SHA256(p_sender * P_receiver)
(也就是 ECDH 算法)offset = HMAC(shared_secret, CHANGE_KEY_CONSTANT)
其中 CHANGE_KEY_CONSTANT
是由协议定义的任意常量P_change = (offset + p_sender) * G
relationship_seed = HMAC(shared_secret, RELATIONSHIP_SEED_CONSTANT)
,其中 RELATIONSHIP_SEED_CONSTANT
是由协议定义的任意常量,不能等于 CHANGE_KEY_CONSTANT
P_change
接收者根据下列检查来观测收款地址并响应收到的交易:
P_sender
是发送者密钥输入的相关 公钥p_receiver
是接收者所用的 Taproot 地址的私钥shared_secret = SHA256(P_sender * p_receiver)
(也就是 ECDH 算法)offset = HMAC(shared_secret, CHANGE_KEY_CONSTANT)
P_change = offset * G + P_sender
P_change
与发送者在找零输出中使用的公钥相匹配relationship_seed = HMAC(shared_secret, RELATIONSHIP_SEED_CONSTANT)
并安全地缓存relationship_seed
,预先计算出足够多数量的 offsetP_i = (offset_i + p_receiver) * G
每次发送者想要给接收者支付时,就计算 P_i = offset_i * G + P_receiver
,其中 offset_i
是使用上述步骤 9 相同的伪随机数生成器产生的一个随机 nonce 值。然后发送者将资金发到 P_i
。接收者预先缓存了这些地址和私钥,所以 TA 可以容易地识别出发送来的交易,并在需要的时候花费其中的资金。
在数据丢失的情形中,发送者可以使用这一套算法来复原交易历史、资金和关系:
shared_secret
和找零输出的算法,并检查推到出的找零输出是否与交易中的某个输出相匹配shared_secret
,并检查预期的找零输出是否与交易的 Taproot 输出相匹配如上所示,通知交易看起来就像真实的交易一样。因为外部观察者无法计算 shared_secret
(假设 ECDH 是安全的),他们就不知道支付双方使用了这套协议,也无法计算出后续的地址。这套协议像 BIP47 一样优于隐身地址,但除此之外,通知地址还无法被外部观察者识别出来,找零输出也并不必然是有毒的(依然推荐混币),开销也相对较小。
虽然看起来开销好像是 0,但并非如此。使用这套协议的通知交易的开销是:
可以说,在多种多样的交易批处理技巧被广泛使用之前,这套协议的开销都相对较小。
很棒的文章。你把它写出来真的很有意义。因为 Taproot 会直接暴露公钥,所以事情会变得简单很多。
你的协议变种重新引入了最初的隐身地址提议希望避免的问题:必须为区块链上的(几乎)每一笔交易计算一个共享秘密值。因为你不可能知道什么时候会有一个新的交易对手想跟你建立一个共享秘密值,所以你必须永远保持扫描状态。椭圆曲线的乘法并不便宜(尤其在不是跟 G 相乘的时候),但这基本上可以视为运行一个全节点(以及恢复备份)来获得更多隐私性的额外验证成本。
可能更大的问题是,在你的协议中,发送者不得不遵循一个特殊的协议来恢复钱包,这可能会导致人们不想使用它,尤其在他们不怎么在乎隐私性的场合。
但我相信一个更简单的协议就足够了,还可以消除发送者一端的复杂性。Bob(B) 可以不必标记找零输出,而是直接给 Alice 的隐身公钥(A) 支付:把资金发到
A' = hash(b * A) + A
。这样发送者就不必制作特殊的找零输出,而且支付可以立即进行,而接收方的成本是一样的,因为现有的协议已经要求了接收者扫描每一笔交易。我能想到的缺点有 3 个:
- 如果 Bob 复用了密钥并发起了第二笔交易,接收的地址就是一样的。这可以通过在共享秘密哈希值中加入更多信息来缓解,比如 Bob 的输入的 txid 或者当前区块高度的 nlock 字段。
- 用 CoinJoin 来支付就不可行了,如果要用第一个输入的话。扫描每一个输入而非每一笔交易的第一个输入可以解决这个问题(但成本会更高)。
- 除非每个人都配合,否则你可能无法用自己并不完全控制的输出(交易所或者多签名)来给隐身公钥支付。但在你的协议中,这依然是可以做到的(虽然有点麻烦),只需要先建立一个共享秘密值,推导出一个新的地址,然后就可以在别的地方发起支付。
也可以像我上面说的一样,仅发起第一笔支付来保留支付码,然后继续为该支付码使用共享秘密值。但我认为,像上面那样省去支付码的简洁性有许多的优点,而缺点是相对较小的。
不管怎么说,很高兴看到你重新拾起了这个话题。在 Taproot 出现的时候,我一直很想重温这个话题,但完全忘记了。
- 本文转载自: btcstudy.org/2022/06/27/... , 如有侵权请联系管理员删除。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!