區塊鏈上的 RSA 隨機數

有一個問題——在去中心化網路中很難產生隨機數。 幾乎所有的區塊鏈都已經遇到過這種情況。 事實上,在用戶之間不存在信任的網路中,創建不可否認的隨機數可以解決許多問題。

在本文中,我們以遊戲為例告訴您如何解決該問題。 其中第一個是 波浪聖誕樹。 為了開發,我們需要一個隨機數產生器。

區塊鏈上的 RSA 隨機數

最初,我們計劃根據區塊鏈中的信息產生一個數字。 然而,後來情況變得很清楚:該數字可以被操縱,這意味著該解決方案不合適。

我們想出了一個解決方法:使用提交-擴展方案。 伺服器猜測 1 到 5 之間的數字,為其添加鹽,然後使用 Keccak 函數。 伺服器提前部署了已經儲存的號碼的智慧合約。 事實證明,遊戲歸結為用戶猜測哈希隱藏的數字。

玩家下注,伺服器將隱藏的數字和“鹽”發送到智能合約。 簡單來說,他亮出了底牌。 之後,伺服器檢查數字並決定用戶是輸還是贏。

如果伺服器沒有發送數字或「鹽」進行驗證,則使用者獲勝。 在這種情況下,對於每場比賽都需要提前部署智能合約並將潛在的獎金納入其中。 結果證明這是不方便、耗時且昂貴的。 當時沒有其他安全的解決方案。

最近,Tradisys團隊提議在Waves協定中加入一個功能 rsa驗證()。 它根據公鑰和私鑰檢查 RSA 簽章的有效性。 結果,添加了該功能。

我們開發了三款遊戲: 擲骰子, Coin Flip и 乘風破浪。 每一個都實現了隨機數技術。 讓我們弄清楚它是如何工作的。

區塊鏈上的 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 遊戲均基於所述的演算法運行。 這就是區塊鏈遊戲的運作方式。 一切都是透明且可驗證的。 在任何其他區塊鏈中都沒有類似的系統。 這是一個公平的隨機。

來源: www.habr.com

添加評論