RSA случајно на блокчејн

Има проблем - тешко е да се генерира случаен број во децентрализирана мрежа. Речиси сите блокчејнови веќе се сретнаа со ова. Навистина, во мрежи каде што нема доверба меѓу корисниците, создавањето на непобитен случаен број решава многу проблеми.

Во оваа статија ви кажуваме како успеавме да го решиме проблемот користејќи игри како пример. Првиот од нив беше Бранови Божиќното дрво. За развој, ни требаше генератор на случаен број.

RSA случајно на блокчејн

Првично, планиравме да генерираме број врз основа на информации од блокчејнот. Сепак, тогаш стана јасно: со бројката може да се манипулира, што значи дека решението не е соодветно.

Дојдовме до решение: користете ја шемата за обврзување-проширување. Серверот погоди број од 1 до 5, додаде сол на него и потоа го хаши резултатот користејќи Кечак функции. Серверот однапред го распореди паметниот договор со веќе зачуваниот број. Излегува дека играта се сведува на тоа корисникот да го погоди бројот скриен од хашот.

Играчот се обложил, а серверот го испратил скриениот број и „сол“ до паметниот договор. Со едноставни зборови, тој ги откри картите. После тоа, серверот ги проверувал броевите и одлучил дали корисникот победил или изгубил.

Ако серверот не испрати број или „сол“ за верификација, корисникот победи. Во овој случај, за секоја игра беше неопходно однапред да се распореди паметен договор и да се вклучат потенцијални добивки во него. Се покажа дека е незгодно, одзема многу време и скапо. Во тоа време немаше друго безбедно решение.

Неодамна, тимот на Tradisys предложи да се додаде функција на протоколот Waves rsaVerify(). Ја проверува валидноста на потписот RSA врз основа на јавниот и приватниот клуч. Како резултат на тоа, функцијата беше додадена.

Развивме три игри: Коцка ролери, Флип на монети и Возење по бранови. Секој од нив имплементира технологија со случаен број. Ајде да дознаеме како функционира.

RSA случајно на блокчејн

Ајде да погледнеме како генерираме случаен број користејќи Ride on Waves како пример. Паметниот договор може да се најде тука.

Одете на јазичето Скрипта и изберете Декомпајлиран. Ќе го видите кодот за паметен договор (ака скрипта).

RSA случајно на блокчејн

Кодот за паметен договор содржи збир на функции. Оние означени како @Callable може да се стартуваат со користење Трансакции со повикување. Ние сме заинтересирани за две функции: обложувам и се повлече:

  • функциски облог (playerChoice)
  • функциско повлекување (Идентификација на играта, rsaSign)

1. Корисникот ја избира должината на сегментот и големината на облогот.

RSA случајно на блокчејн

2. Клиентот создава функција за обложување. За сликата погоре тоа би било облог („50“).

3. Клиентот испраќа трансакција за повикување на адресата на паметниот договор (broadcast InvocationTx). Трансакцијата ја содржи функцијата облог како параметар за повик. Ова значи дека трансакцијата Invocation го активира извршувањето на функцијата за обложување (избор: Низа) на паметниот договор.

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. ИД на играта на новата игра е веќе снимен во блокчејнот, што значи дека повеќе не може да се менува или да се влијае на него.

6. Серверот генерира функција за повлекување (gameId, rsaSign). На пример, вака:

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

7. Серверот испраќа трансакција Invocation до паметниот договор (broadcast InvocationTx). Трансакцијата содржи повик до формираната функција за повлекување (gameId, rsaSign):

RSA случајно на блокчејн

Функцијата содржи ид на играта нова игра и резултат од потпишувањето на RSA на единствен идентификатор со приватен клуч. Резултатот од потписот е непроменет.

Што значи ова?

Ја земаме истата вредност (ид на играта) и го применуваме методот на потпис RSA на неа. Секогаш ќе го добиваме истиот резултат. Вака функционира алгоритмот RSA. Конечниот број не може да се манипулира, бидејќи идентификацијата на играта и резултатот од примената на RSA не се познати. Изборот на број е исто така бесмислен.

8. Блокчејн ја прифаќа трансакцијата. Ја извршува функцијата за повлекување (gameId, rsaSign)

9. Внатре во функцијата за повлекување се случува повлекување GenerateRandInt функции (Идентификација на играта, 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 ид на играта приватен клуч (rsaSign). Потоа се хашира со SHA-256 (sha256 (rsaSign)).

Не можеме да го предвидиме исходот од потписот и последователното хаширање. Затоа, невозможно е да се влијае на генерирањето на случаен број. За да добиете број во одреден опсег (на пример, од 1 до 100), користете ја функцијата за конверзија toInt и %100 (слично на МО).

На почетокот на статијата ја споменавме функцијата rsaVerify(), кој ви овозможува да ја проверите валидноста на потписот RSA користејќи приватен клуч наспроти јавен. Еве го делот GenerateRandInt(gameId,rsaSign):

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

Јавниот клуч RSAPUBLIC и низата rsaSign се пренесуваат на влезот. Потписот се проверува за валидност. Бројот се генерира ако проверката е успешна. Во спротивно, системот смета дека потписот не е валиден (Invalid RSA signature).

Серверот мора да го потпише идентификаторот на играта со приватен клуч и да испрати валиден потпис Rsa во рок од 2880 блокови. Параметарот е конфигуриран при распоредување на паметниот договор. Ако ништо не се случи во даденото време, корисникот победи. Во овој случај, наградата мора сами да се испрати на вашата адреса. Излегува дека „не е профитабилно за серверот да мами“, бидејќи тоа води до загуба. Подолу е пример.

RSA случајно на блокчејн

Корисникот игра Коцка ролери. Избрав 2 од 6-те страни на коцката, облогот е 14 БРАНОВИ. Доколку серверот не испрати важечки потпис на RSA на паметниот договор во одреденото време (2880 блокови), корисникот ќе земе 34.44 БРАНОВИ.

За да генерираме броеви во игрите, користиме пророк - надворешен, не-блокчејн систем. Серверот врши RSA потпис на идентификацијата на играта. Паметниот договор ја проверува валидноста на потписот и го одредува победникот. Ако серверот не испрати ништо, тогаш корисникот автоматски победува.

Ова е чесен метод за генерирање, бидејќи манипулацијата е технички невозможна. Сите игри на Tradisys работат врз основа на опишаниот алгоритам. Вака функционираат блокчејн игрите. Сè е транспарентно и проверливо. Нема аналози на таков систем во кој било друг блокчејн. Ова е фер случаен избор.

Извор: www.habr.com

Додадете коментар