RSA atsitiktinis blokų grandinėje

Iškilo problema – decentralizuotame tinkle sunku sugeneruoti atsitiktinį skaičių. Beveik visos blokų grandinės su tuo jau susidūrė. Iš tiesų tinkluose, kuriuose nėra vartotojų pasitikėjimo, neginčijamo atsitiktinio skaičiaus sukūrimas išsprendžia daugybę problemų.

Šiame straipsnyje mes jums pasakysime, kaip mums pavyko išspręsti problemą naudojant žaidimus kaip pavyzdį. Pirmasis iš jų buvo Bangos Kalėdų eglutė. Norėdami sukurti, mums reikėjo atsitiktinių skaičių generatoriaus.

RSA atsitiktinis blokų grandinėje

Iš pradžių planavome sugeneruoti skaičių pagal informaciją iš blockchain. Tačiau tada paaiškėjo: skaičiumi galima manipuliuoti, vadinasi, sprendimas netinkamas.

Mes sugalvojome sprendimą: naudokite įpareigojimo-išplėtimo schemą. Serveris atspėjo skaičių nuo 1 iki 5, įdėjo į jį druskos ir tada naudojo rezultato maišą Keccak funkcijos. Serveris iš anksto įdiegė išmaniąją sutartį su jau išsaugotu numeriu. Pasirodo, žaidimas susiveda į tai, kad vartotojas atspėja maišos paslėptą skaičių.

Žaidėjas atliko statymą, o serveris nusiuntė paslėptą skaičių ir „druską“ į išmaniąją sutartį. Paprastais žodžiais tariant, jis atskleidė kortas. Po to serveris patikrino skaičius ir nusprendė, ar vartotojas laimėjo, ar pralaimėjo.

Jei serveris neatsiuntė numerio ar „druskos“ patvirtinimui, vartotojas laimėjo. Tokiu atveju kiekvienam žaidimui reikėjo iš anksto sudaryti išmaniąją sutartį ir į ją įtraukti galimus laimėjimus. Tai pasirodė nepatogu, daug laiko ir brangu. Tuo metu kito saugaus sprendimo nebuvo.

Neseniai „Tradisys“ komanda pasiūlė į „Waves“ protokolą įtraukti funkciją rsaPatvirtinti(). Jis tikrina RSA parašo galiojimą pagal viešąjį ir privatųjį raktą. Dėl to funkcija buvo pridėta.

Mes sukūrėme tris žaidimus: Kauliukų volelis, Coin Flip и Ride On Waves. Kiekvienas iš jų įgyvendina atsitiktinių skaičių technologiją. Išsiaiškinkime, kaip tai veikia.

RSA atsitiktinis blokų grandinėje

Pažiūrėkime, kaip sugeneruoti atsitiktinį skaičių, kaip pavyzdį naudojant Ride on Waves. Išmaniąją sutartį galima rasti čia.

Eikite į skirtuką Scenarijus ir pasirinkite Dekompiliuota. Pamatysite išmaniosios sutarties kodą (dar žinomą kaip scenarijus).

RSA atsitiktinis blokų grandinėje

Išmaniajame sutarties kode yra funkcijų rinkinys. Tie, kurie pažymėti kaip @Callable, gali būti paleisti naudojant Iškvietimo operacijos. Mus domina dvi funkcijos: lažybos и atšaukti:

  • func bet (žaidėjo pasirinkimas)
  • funkcijos atšaukimas (gameId, rsaSign)

1. Vartotojas pasirenka segmento ilgį ir statymo dydį.

RSA atsitiktinis blokų grandinėje

2. Klientas sukuria statymo funkciją. Aukščiau pateiktame paveikslėlyje taip būtų statymas ("50").

3. Klientas siunčia iškvietimo operaciją išmaniosios sutarties adresu (transliacija InvocationTx). Sandoryje yra statymo funkcija kaip skambinimo parametras. Tai reiškia, kad iškvietimo operacija suaktyvina statymo funkcijos (pasirinkimas: eilutė) vykdymą išmaniojoje sutartyje.

RSA atsitiktinis blokų grandinėje

4. Apsvarstykite statymo funkciją:

@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)))
                    }
    }

Funkcija įrašo naują žaidimą į išmaniosios sutarties būseną. Būtent:

  • Unikalus naujo žaidimo identifikatorius (žaidimo ID)
  • Žaidimo būsena = PATEIKTA
  • Žaidėjo pasirinkimas (segmento ilgis 50)
  • Viešasis raktas
  • Galimi laimėjimai (priklausomai nuo žaidėjo statymo)

RSA atsitiktinis blokų grandinėje

Taip atrodo duomenų įrašas blokų grandinėje (rakto vertė):

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

„Raktas“ (raktas) – žaidimo id Naujas žaidimas. Likę duomenys yra „vertės“ lauko eilutėje. Šie įrašai saugomi skirtuke Duomenys protinga sutartis:

RSA atsitiktinis blokų grandinėje

RSA atsitiktinis blokų grandinėje

5. Serveris „pažiūri“ į išmaniąją sutartį ir suranda atsiųstą transakciją (naują žaidimą), naudodamas blockchain Api. Naujo žaidimo žaidimo ID jau įrašytas blokų grandinėje, vadinasi, jo keisti ar paveikti nebegalima

6. Serveris sugeneruoja atšaukimo funkciją (gameId, rsaSign). Pavyzdžiui, taip:

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

7. Serveris siunčia iškvietimo operaciją į išmaniąją sutartį (transliuoti InvocationTx). Operacijoje yra iškvietimas į suformuotą išėmimo funkciją (gameId, rsaSign):

RSA atsitiktinis blokų grandinėje

Funkcija apima žaidimo id naujas žaidimas ir unikalaus identifikatoriaus RSA pasirašymo privačiu raktu rezultatas. Parašo rezultatas nesikeičia.

Ką tai reiškia?

Paimame tą pačią reikšmę (žaidimo ID) ir jai taikome RSA parašo metodą. Visada gausime tą patį rezultatą. Taip veikia RSA algoritmas. Galutiniu skaičiumi manipuliuoti negalima, nes žaidimo ID ir RSA taikymo rezultatas nežinomi. Rinktis skaičių taip pat beprasmiška.

8. Blockchain priima sandorį. Jis vykdo atšaukimo funkciją (gameId, rsaSign)

9. Atsitraukimo funkcijos viduje įvyksta pasitraukimas GenerateRandInt funkcijos (gameId, rsaSign). Tai yra atsitiktinių skaičių generatorius

# @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")
    }

eilė - ir yra atsitiktinis skaičius.

Pirmiausia paimama eilutė, kuri yra RSA parašo rezultatas žaidimo id privatus raktas (rsaSign). Tada maišoma naudojant SHA-256 (sha256 (rsaSign)).

Negalime numatyti parašo ir vėlesnės maišos rezultatų. Todėl neįmanoma įtakoti atsitiktinio skaičiaus generavimo. Norėdami gauti skaičių tam tikrame diapazone (pvz., nuo 1 iki 100), naudokite konvertavimo funkciją toInt ir %100 (panašiai kaip mod).

Straipsnio pradžioje paminėjome funkciją rsaPatvirtinti(), kuri leidžia patikrinti RSA parašo galiojimą naudojant privatų raktą, palyginti su viešuoju. Štai dalis GenerateRandInt(gameId,rsaSign):

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

Viešasis raktas RSAPUBLIC ir rsaSign eilutė perduodami į įvestį. Patikrinamas parašo galiojimas. Skaičius sugeneruojamas sėkmingai patikrinus. Priešingu atveju sistema mano, kad parašas negalioja (Netinkamas RSA parašas).

Serveris turi pasirašyti žaidimo ID privačiu raktu ir išsiųsti galiojantį Rsa parašą per 2880 blokų. Parametras sukonfigūruojamas diegiant išmaniąją sutartį. Jei per nustatytą laiką nieko neįvyksta, vartotojas laimi. Tokiu atveju prizas turi būti išsiųstas jūsų adresu pats. Pasirodo, „serveriui neapsimoka sukčiauti“, nes tai sukelia nuostolius. Žemiau yra pavyzdys.

RSA atsitiktinis blokų grandinėje

Vartotojas žaidžia Kauliukų volelis. Aš pasirinkau 2 iš 6 kubo pusių, statymas yra 14 BANGŲ. Jei serveris per nurodytą laiką (2880 blokų) neišsiunčia galiojančio RSA parašo prie išmaniosios sutarties, vartotojas paims 34.44 BANGAS.

Skaičiams žaidimuose generuoti naudojame orakulą – išorinę, be blokų grandinės sistemą. Serveris atlieka žaidimo ID RSA parašą. Išmanioji sutartis patikrina parašo galiojimą ir nustato laimėtoją. Jei serveris nieko nesiunčia, vartotojas automatiškai laimi.

Tai sąžiningas generavimo metodas, nes manipuliuoti techniškai neįmanoma. Visi Tradisys žaidimai veikia pagal aprašytą algoritmą. Taip veikia „blockchain“ žaidimai. Viskas aišku ir patikrinama. Tokios sistemos analogų nėra jokioje kitoje blokų grandinėje. Tai sąžiningas atsitiktinumas.

Šaltinis: www.habr.com

Добавить комментарий