Pay-to-Contract and Sign-to-Contract Commitment
Table of Contents
1. 背景简介
怎么在 BTC 区块链上提交一个 Commitment 呢?一个可行的办法是在 Tx 的 Output 中使用 OP_RETURN 提交。不过,这种方式会增加 Tx 的大小,增加手续费。
本文介绍其它两种往 BTC 区块链上提交 Commitment 的办法。
2. Pay-to-Contract
假如 Bob 要给 Alice 转一些 BTC,同时 Bob 还想把某个 Commitment 值(如某个文档的哈希值 s)也提交到链上去。
假设 Bob 知道了 Alice 的公钥 A:
A = a * G // a 是 Alice 的私钥,A 是相应公钥,Alice 地址由公钥 A 推导出来
Bob 不直接把 BTC 转给 Alice 的地址,而是 把 BTC 转到下面公钥(Q)对应的地址:
Q = A + h(A || s) * G // A 是 Alice 的公钥, || 表示concatenate
这个公钥 Q 对应的私钥为:
q = a + h(A || s) ^ ^ | | | Bob 掌握 | Alice 掌握
当 Bob 把 s 值告诉 Alice 后,Alice 就完全掌握了公钥 Q 对应的私钥 q。
这样,Bob 给 Alice 转 BTC 的同时往链上提交了一个 Commitment s。一旦 s 背后的原始文档被 Bob 公开,所有人都可以验证 Bob 确实在这笔转账之前就已经掌握了 s 背后的原始文档(注:如果这个文档记录着某个未公开的研究成果,则 Bob 可以验证他在这笔转账前就掌握了这个研究成果)。
Pay-to-Contract 有个不足: 如果 Alice 暂时不想使用 Bob 给她转的 BTC,则她需要对 s 进行备份(因为计算私钥 q 时需要 s),如果没有备份 s,可能导致资产损失。
2.1. Pay-to-Contract 原始论文
Pay-to-Contract 由 Ilja Gerhardt 和 Timo Hanke 于 2012 年在论文 Homomorphic Payment Addresses and the Pay-to-Contract Protocol 中提出。
论文中描述了 Customer 浏览 Merchant 网站购买东西的场景。图 1 是一种传统的方案,用户提交订单后,Merchant 网站后台生成一个付款地址后返回给用户。这种方式不是很安全,论文作者提出了图 2 所示的 Pay-to-Contract 方案,付款地址由 Customer 端根据合约(前面介绍中的 s )推导出来。
Figure 1: 传统的方案
Figure 2: Pay-to-Contract 方案
3. Sign-to-Contract
前面提到,Pay-to-Contract 有个不足:暂时不花费 UTXO 的话,需要小心备份 Commitment。Sign-to-Contract 可以避免 Pay-to-Contract 的这个缺点。
Sign-to-Contract 的思路是 把 Commitment 嵌入到 Tx Input 中的签名数据中。
回顾一下 ECDSA 签名:
def ECDSAsign(x,m): k = deterministic_nonce(x,m) R = k*G r = R.x mod n s = k^(-1) * (m + r*x) mod n return (r,s)
签名数据是 (r,s)
。
签名过程中,有个 R 值,它一般需要随机产生;在 Deterministic ECDSA 中,它是由私钥 x 和待签名消息 m 确定产生的。
对于 Sign-to-Contract,关键步骤就是使用下面值 Q 来替换 R:
Q = R + h(R||s) * G // Sign-to-Contract 所使用的新 R 值
具体来说,过程如下:
def ECDSAsign2contract(x,m,s): k = deterministic_nonce(x,m) R = k*G e = k + h(R||s) Q = R + h(R||s) * G // Q = e*G,相关于 ECDSAsign 中的 R q = Q.x mod n z = e^(-1) * (m + q*x) mod n return (q,z), R
新的签名数据是 (q,z)
。
揭秘 Commitment 时,公开 s 背后的原始文档和 ECDSAsign2contract 中的 R 值,这样别人就都可以验证 Commitment 了。