在上一篇文章中,我们将 BSV 智能合约泛化为包括可选的链下验证部分,以及由脚本组成的常规链上部分。我们将这一概念应用于抛硬币游戏,通过使用抵押金的方式反向激励两人不要单方面中止游戏。
在本文中,我们使用参考文献[^1]中所述的方法,实现了另外一种公平抛硬币合约,并再次展示了如何设计带有链上和链下部分的混合智能合约。智能合约被定义为一种协议,无需信任方可以根据其交互协议安全地进行交易,而无需受信任的第三方。 安全性取决于特定的合约,通常来说可以包括以下属性:1)遵守合约/协议的诚实方绝不应该赔钱; 2)必须检测出不诚实的不正当方,并可以选择对其进行经济制裁。
无需抵押的公平掷硬币游戏合约
新合约包括以下锁定步骤:
- Alice 和 Bob 互相交换公钥,锁定时间 t 和秘密数字/随机数的哈希;
- Bob 创建 Tx0。使用 Tx0 的 txid,他还创建了 Tx1 ,并把它给了 Alice 。注意此时他还没有签名,否则 Alice 会知道他的秘密;
- Alice 在 Tx1 上签名并将其返回给 Bob;
- Bob 签名并添加了他的秘密。现在 Tx1 完成了,他创建了 Tx3 并将其交给 Alice;
- Alice 签名并返回 Bob,后者广播 Tx0 和 Tx1。Alice 现在知道 Bob 在 Tx1 中的秘密;
- Alice 将她的秘密发送给 Bob,无论谁赢了,都按照原始掷硬币合约的要求发送 Tx2 进而得到获胜奖励。如果 Alice 未在 t 时间之前分享她的秘密,Bob 也可以通过签名并广播 Tx3 从而 “赢得游戏”。
在第 2 步之后的每个步骤中,每一方都会在本地离线验证交易,如果验证失败,则中止交易。这些验证包括:签名,t,秘密哈希和 txid 匹配。合约是安全的,因为 Bob 必须透露自己的秘密来创建 Tx1。Alice 也必须这样做,否则 Bob 将通过广播 Tx3 可以获胜。
Tx0 中的 HashLock
合约如下所示:
contract HashLock {
bytes bobHash;
PubKey bob;
public function open(bytes bobNonce, Sig bobSig) {
require(sha256(bobNonce) == this.bobHash);
require(checkSig(bobSig, this.bob));
}
}
Tx1 中的 CoinToss 合约与之前相似,不同之处在于添加了一个函数 forfeit()
。
contract CoinToss {
// same as before ...
public function toss(bytes aliceNonce, bytes bobNonce, Sig sig) {
// same as before ...
}
public function forfeit(Sig aliceSig, Sig bobSig) {
require(checkSig(aliceSig, this.alice));
require(checkSig(bobSig, this.bob));
}
}
[1] Secure Multiparty Computations on Bitcoin · Marcin Andrychowicz, Stefan Dziembowski, L. Mazurek. 2014 IEEE Symposium on Security and Privacy