区块链上的 RSA 随机数

有一个问题——在去中心化网络中很难生成随机数。 几乎所有的区块链都已经遇到过这种情况。 事实上,在用户之间不存在信任的网络中,创建不可否认的随机数可以解决许多问题。

在本文中,我们以游戏为例告诉您如何解决该问题。 其中第一个是 波浪圣诞树。 为了开发,我们需要一个随机数生成器。

区块链上的 RSA 随机数

最初,我们计划根据区块链中的信息生成一个数字。 然而,后来情况变得很清楚:该数字可以被操纵,这意味着该解决方案不合适。

我们想出了一个解决方法:使用提交-扩展方案。 服务器猜测 1 到 5 之间的数字,为其添加盐,然后使用 Keccak 函数。 服务器提前部署了已经保存的号码的智能合约。 事实证明,游戏归结为用户猜测哈希隐藏的数字。

玩家下注,服务器将隐藏的数字和“盐”发送到智能合约。 简单来说,他亮出了底牌。 之后,服务器检查数字并决定用户是输还是赢。

如果服务器没有发送数字或“盐”进行验证,则用户获胜。 在这种情况下,对于每场比赛都需要提前部署智能合约并将潜在的奖金包含在其中。 结果证明这是不方便、耗时且昂贵的。 当时没有其他安全的解决方案。

最近,Tradisys团队提议在Waves协议中添加一个功能 rsa验证()。 它根据公钥和私钥检查 RSA 签名的有效性。 结果,添加了该功能。

我们开发了三款游戏: 滚子说, 硬币翻转 и 乘风破浪。 每一个都实现了随机数技术。 让我们弄清楚它是如何工作的。

区块链上的 RSA 随机数

让我们以 Ride on Waves 为例来看看生成随机数。 可以找到智能合约 这里.

转到标签 脚本 然后选择 反编译。 您将看到智能合约代码(又名脚本)。

区块链上的 RSA 随机数

智能合约代码包含一组函数。 那些标记为 @Callable 的可以使用以下命令启动 调用交易。 我们对两个函数感兴趣: 打赌 и 退出:

  • 功能投注(玩家选择)
  • func 提款(游戏 ID,rsaSign)

1. 用户选择片段的长度和赌注大小。

区块链上的 RSA 随机数

2. 客户端创建下注函数。 对于上面的图片来说,它是 下注(“50”).

3. 客户端向智能合约地址发送调用交易(广播InvoiceTx)。 该交易包含下注函数作为调用参数。 这意味着调用交易会触发智能合约上投注函数(选择:字符串)的执行。

区块链上的 RSA 随机数

4. 考虑下注函数:

@Callable(i)
func bet (playerChoice) = {
    let newGameNum = IncrementGameNum()
    let gameId = toBase58String(i.transactionId)
    let pmt = extract(i.payment)
    let betNotInWaves = isDefined(pmt.assetId)
    let feeNotInWaves = isDefined(pmt.assetId)
    let winAmt = ValidateBetAndDefineWinAmt(pmt.amount, playerChoice)
    let txIdUsed = isDefined(getString(this, gameId))
    if (betNotInWaves)
        then throw ("Bet amount must be in Waves")
        else if (feeNotInWaves)
            then throw ("Transaction's fee must be in Waves")
            else if (txIdUsed)
                then throw ("Passed txId had been used before. Game aborted.")
                else {
                    let playerPubKey58 = toBase58String(i.callerPublicKey)
                    let gameDataStr = FormatGameDataStr(STATESUBMITTED, playerChoice, playerPubKey58, height, winAmt, "")
                    ScriptResult(WriteSet(cons(DataEntry(RESERVATIONKEY, ValidateAndIncreaseReservedAmt(winAmt)), cons(DataEntry(GAMESCOUNTERKEY, newGameNum), cons(DataEntry(gameId, gameDataStr), nil)))), TransferSet(cons(ScriptTransfer(SERVER, COMMISSION, unit), nil)))
                    }
    }

该函数将一个新游戏写入智能合约的状态。 即:

  • 新游戏的唯一标识符 (游戏ID)
  • 游戏状态 = 已提交
  • 玩家选择(段长50)
  • 公钥
  • 潜在奖金(取决于玩家的赌注)

区块链上的 RSA 随机数

这就是区块链中数据记录的样子(键值):

{
    "type": "string",
    "value": "03WON_0283_448t8Jn9P3717UnXFEVD5VWjfeGE5gBNeWg58H2aJeQEgJ_06574069_09116020000_0229",
    "key": "2GKTX6NLTgUrE4iy9HtpSSHpZ3G8W4cMfdjyvvnc21dx"
  }

“钥匙”(钥匙)—— 游戏编号 新游戏。 其余数据包含在“值”字段的行中。 这些条目存储在选项卡中 时间 智能合约:

区块链上的 RSA 随机数

区块链上的 RSA 随机数

5. 服务器“查看”智能合约并使用区块链 Api 查找发送的交易(新游戏)。 新游戏的Game id已经记录在区块链中,这意味着它不能再被更改或影响

6. 服务器生成提现函数(gameId,rsaSign)。 例如,像这样:

withdraw ("FwsuaaShC6DMWdSWQ5osGWtYkVbTEZrsnxqDbVx5oUpq", "base64:Gy69dKdmXUEsAmUrpoWxDLTQOGj5/qO8COA+QjyPVYTAjxXYvEESJbSiCSBRRCOAliqCWwaS161nWqoTL/TltiIvw3nKyd4RJIBNSIgEWGM1tEtNwwnRwSVHs7ToNfZ2Dvk/GgPUqLFDSjnRQpTHdHUPj9mQ8erWw0r6cJXrzfcagKg3yY/0wJ6AyIrflR35mUCK4cO7KumdvC9Mx0hr/ojlHhN732nuG8ps4CUlRw3CkNjNIajBUlyKQwpBKmmiy3yJa/QM5PLxqdppmfFS9y0sxgSlfLOgZ51xRDYuS8NViOA7c1JssH48ZtDbBT5yqzRJXs3RnmZcMDr/q0x6Bg==")

7. 服务器向智能合约发送一个调用交易(广播 InvoiceTx)。 该交易包含对所形成的提款函数(gameId、rsaSign)的调用:

区块链上的 RSA 随机数

该函数包含 游戏编号 新游戏以及使用私钥对唯一标识符进行 RSA 签名的结果。 签名结果不变。

这是什么意思呢?

我们采用相同的值(游戏 ID)并对其应用 RSA 签名方法。 我们总是会得到相同的结果。 这就是 RSA 算法的工作原理。 最终的数字无法被操纵,因为游戏 ID 和应用 RSA 的结果是未知的。 选择一个数字也是没有意义的。

8. 区块链接受交易。 它运行取款功能(gameId,rsaSign)

9. 在withdraw函数内部,发生取款 生成 RandInt 函数 (游戏 ID、rsaSign)。 这是一个随机数生成器

# @return 1 ... 100
func GenerateRandInt (gameId,rsaSign) = {
   	# verify RSA signature to proof random
    let rsaSigValid = rsaVerify (SHA256, toBytes(gameId), rsaSign, RSAPUBLIC)
    if (rsaSigValid)
        then {
            let rand = (toInt(sha256(rsaSign)) % 100)
            if ((0 > rand))
                then ((-1 * rand) + 1)
                else (rand + 1)
            }
        else throw ("Invalid RSA signature")
    }

兰特 - 并且有一个随机数。

首先取字符串,这是RSA签名的结果 游戏编号 私钥(RSA签名)。 然后使用 SHA-256 进行哈希处理(sha256(rsaSign)).

我们无法预测签名和后续哈希的结果。 因此,不可能影响随机数的生成。 要获取某个范围内的数字(例如,从 1 到 100),请使用 toInt 转换函数和 %100(类似于 MOD).

文章开头我们提到了这个功能 rsa验证(),它允许您使用私钥与公钥检查 RSA 签名的有效性。 这是GenerateRandInt(gameId,rsaSign)部分:

rsaVerify (SHA256, toBytes(gameId), rsaSign, RSAPUBLIC)

公钥 RSAPUBLIC 和 rsaSign 字符串将传递到输入。 检查签名的有效性。 如果检查成功,则生成该号码。 否则,系统认为签名无效(Invalid RSA Signature)。

服务器必须使用私钥对游戏 ID 进行签名,并在 2880 个区块内发送有效的 Rsa 签名。 该参数是在部署智能合约时配置的。 如果在规定的时间内没有发生任何事情,则用户获胜。 在这种情况下,奖品必须亲自发送到您的地址。 事实证明,“服务器作弊是无利可图的”,因为这会导致损失。 下面是一个例子。

区块链上的 RSA 随机数

用户正在玩 滚子说。 我选择了立方体 2 个面中的 6 个,赌注是 14 WAVES。 如果服务器在指定时间(2880 个区块)内没有向智能合约发送有效的 RSA 签名,则用户将花费 34.44 WAVES。

为了在游戏中生成数字,我们使用预言机 - 一个外部的非区块链系统。 服务器对游戏 ID 执行 RSA 签名。 智能合约检查签名的有效性并确定获胜者。 如果服务器不发送任何内容,则用户自动获胜。

这是一种诚实的生成方法,因为操纵在技术上是不可能的。 所有 Tradisys 游戏均基于所描述的算法运行。 这就是区块链游戏的运作方式。 一切都是透明且可验证的。 在任何其他区块链中都没有类似的系统。 这是一个公平的随机。

来源: habr.com

添加评论