RSA aleatoriu pe blockchain

Există o problemă - este dificil să generați un număr aleatoriu într-o rețea descentralizată. Aproape toate blockchain-urile au întâlnit deja acest lucru. Într-adevăr, în rețelele în care nu există încredere între utilizatori, crearea unui număr aleatoriu incontestabil rezolvă multe probleme.

În acest articol vă spunem cum am reușit să rezolvăm problema folosind jocuri ca exemplu. Primul dintre ei a fost Waves Pomul de Crăciun. Pentru dezvoltare, aveam nevoie de un generator de numere aleatorii.

RSA aleatoriu pe blockchain

Inițial, am plănuit să generăm un număr pe baza informațiilor din blockchain. Cu toate acestea, atunci a devenit clar: numărul putea fi manipulat, ceea ce înseamnă că soluția nu este potrivită.

Am venit cu o soluție: folosiți schema commit-expand. Serverul a ghicit un număr de la 1 la 5, i-a adăugat o sare și apoi a analizat rezultatul folosind Funcții Keccak. Serverul a implementat contractul inteligent cu numărul deja salvat în avans. Se pare că jocul se rezumă la faptul că utilizatorul ghiceste numărul ascuns de hash.

Jucătorul a plasat un pariu, iar serverul a trimis numărul ascuns și „sare” la contractul inteligent. În termeni simpli, el a dezvăluit cărțile. După aceea, serverul a verificat numerele și a decis dacă utilizatorul a câștigat sau a pierdut.

Dacă serverul nu a trimis un număr sau „sare” pentru verificare, utilizatorul a câștigat. În acest caz, pentru fiecare joc a fost necesară implementarea unui contract inteligent în prealabil și includerea potențialelor câștiguri în acesta. S-a dovedit a fi incomod, consumator de timp și costisitor. La acel moment nu exista o altă soluție sigură.

Recent, echipa Tradisys a propus adăugarea unei funcții la protocolul Waves rsaVerify(). Acesta verifică validitatea semnăturii RSA pe baza cheii publice și private. Ca rezultat, funcția a fost adăugată.

Am dezvoltat trei jocuri: Spune Roller, Coin Flip и Ride On Waves. Fiecare implementează tehnologia numerelor aleatorii. Să ne dăm seama cum funcționează.

RSA aleatoriu pe blockchain

Să ne uităm la generarea unui număr aleatoriu folosind Ride on Waves ca exemplu. Contractul inteligent poate fi găsit aici.

Accesați fila Scenariu și selectați Decompilat. Veți vedea codul de contract inteligent (aka script).

RSA aleatoriu pe blockchain

Codul de contract inteligent conține un set de funcții. Cele marcate ca @Callable pot fi lansate folosind Tranzacții de invocare. Suntem interesați de două funcții: pariu и retrage:

  • func bet (playerChoice)
  • func draw(gameId,rsaSign)

1. Utilizatorul selectează lungimea segmentului și dimensiunea pariului.

RSA aleatoriu pe blockchain

2. Clientul creează o funcție de pariu. Pentru imaginea de mai sus ar fi pariu("50").

3. Clientul trimite o tranzacție de invocare la adresa smart contract (difuzare InvocationTx). Tranzacția conține funcția de pariu ca parametru de apel. Aceasta înseamnă că tranzacția de invocare declanșează execuția funcției de pariu (alegerea: String) pe contractul inteligent.

RSA aleatoriu pe blockchain

4. Luați în considerare funcția de pariu:

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

Funcția scrie un nou joc în starea contractului inteligent. Și anume:

  • Identificator unic pentru un joc nou (ID joc)
  • Stare joc = SUBMITTED
  • Alegerea jucătorului (lungimea segmentului 50)
  • Cheie publică
  • Câștiguri potențiale (în funcție de pariul jucătorului)

RSA aleatoriu pe blockchain

Iată cum arată o înregistrare de date în blockchain (cheie-valoare):

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

„Cheie” (cheie) – ID joc joc nou. Datele rămase sunt conținute în linia câmpului „valoare”. Aceste intrări sunt stocate în filă Date contract inteligent:

RSA aleatoriu pe blockchain

RSA aleatoriu pe blockchain

5. Serverul „se uită” la contractul inteligent și găsește tranzacția trimisă (joc nou) folosind Api-ul blockchain. Id-ul jocului noului joc este deja înregistrat în blockchain, ceea ce înseamnă că nu mai poate fi schimbat sau influențat

6. Serverul generează o funcție de retragere (gameId, rsaSign). De exemplu, așa:

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

7. Serverul trimite o tranzacție de invocare către contractul inteligent (difuzare InvocationTx). Tranzacția conține un apel la funcția de retragere formată (gameId, rsaSign):

RSA aleatoriu pe blockchain

Funcția conține ID joc joc nou și rezultatul semnării RSA a unui identificator unic cu o cheie privată. Rezultatul semnăturii este neschimbat.

Ce înseamnă?

Luăm aceeași valoare (id-ul jocului) și îi aplicăm metoda semnăturii RSA. Vom obține întotdeauna același rezultat. Acesta este modul în care funcționează algoritmul RSA. Numărul final nu poate fi manipulat, deoarece id-ul jocului și rezultatul aplicării RSA nu sunt cunoscute. Alegerea unui număr este, de asemenea, inutilă.

8. Blockchain acceptă tranzacția. Rulează funcția de retragere (gameId, rsaSign)

9. În interiorul funcției de retragere, are loc retragerea Funcții GenerateRandInt (gameId, rsaSign). Acesta este un generator de numere aleatorii

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

rand - și există un număr aleatoriu.

În primul rând, este preluat șirul, care este rezultatul semnăturii RSA ID joc cheie privată (rsaSign). Apoi hashing cu SHA-256 (sha256(rsaSign)).

Nu putem prezice rezultatul semnăturii și al hashingului ulterioară. Prin urmare, este imposibil să influențezi generarea unui număr aleatoriu. Pentru a obține un număr într-un anumit interval (de exemplu, de la 1 la 100), utilizați funcția de conversie toInt și %100 (similar cu Mod).

La începutul articolului am menționat funcția rsaVerify(), care vă permite să verificați validitatea unei semnături RSA folosind o cheie privată față de una publică. Iată partea GenerateRandInt(gameId,rsaSign):

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

Cheia publică RSAPUBLIC și șirul rsaSign sunt transmise la intrare. Semnătura este verificată pentru valabilitate. Numărul este generat dacă verificarea are succes. În caz contrar, sistemul consideră că semnătura nu este validă (semnătură RSA invalidă).

Serverul trebuie să semneze id-ul jocului cu o cheie privată și să trimită o semnătură Rsa validă în 2880 de blocuri. Parametrul este configurat la implementarea contractului inteligent. Dacă nu se întâmplă nimic în timpul alocat, utilizatorul câștigă. În acest caz, premiul trebuie trimis chiar la adresa dumneavoastră. Se dovedește că „nu este profitabil ca serverul să trișeze”, deoarece acest lucru duce la pierderi. Mai jos este un exemplu.

RSA aleatoriu pe blockchain

Utilizatorul se joacă Spune Roller. Am ales 2 din cele 6 laturi ale cubului, pariul este 14 VALURI. Dacă serverul nu trimite o semnătură RSA validă către contractul inteligent în timpul specificat (2880 de blocuri), utilizatorul va lua 34.44 UNDURI.

Pentru a genera numere în jocuri, folosim un oracol - un sistem extern, non-blockchain. Serverul efectuează o semnătură RSA a ID-ului jocului. Contractul inteligent verifică valabilitatea semnăturii și determină câștigătorul. Dacă serverul nu trimite nimic, atunci utilizatorul câștigă automat.

Aceasta este o metodă de generare cinstită, deoarece manipularea este imposibilă din punct de vedere tehnic. Toate jocurile Tradisys funcționează pe baza algoritmului descris. Așa funcționează jocurile blockchain. Totul este transparent și verificabil. Nu există analogi ai unui astfel de sistem în niciun alt blockchain. Aceasta este o întâmplare corectă.

Sursa: www.habr.com

Adauga un comentariu