RSA-Zufall auf Blockchain

Es gibt ein Problem: In einem dezentralen Netzwerk ist es schwierig, eine Zufallszahl zu generieren. Bei fast allen Blockchains ist dies bereits aufgetreten. Tatsächlich löst die Erstellung einer unbestreitbaren Zufallszahl in Netzwerken, in denen kein Vertrauen zwischen Benutzern besteht, viele Probleme.

In diesem Artikel erzählen wir Ihnen am Beispiel von Spielen, wie wir das Problem lösen konnten. Der erste von ihnen war Wellen-Weihnachtsbaum. Für die Entwicklung benötigten wir einen Zufallszahlengenerator.

RSA-Zufall auf Blockchain

Ursprünglich hatten wir geplant, eine Nummer basierend auf Informationen aus der Blockchain zu generieren. Doch dann wurde klar: Die Zahl könnte manipuliert sein, die Lösung sei also nicht geeignet.

Wir haben einen Workaround gefunden: Verwenden Sie das Commit-Expand-Schema. Der Server hat eine Zahl von 1 bis 5 erraten, ein Salz hinzugefügt und das Ergebnis dann mit gehasht Keccak-Funktionen. Der Server hat den Smart Contract mit der bereits gespeicherten Nummer im Voraus bereitgestellt. Es stellt sich heraus, dass das Spiel darauf hinausläuft, dass der Benutzer die durch den Hash verborgene Zahl errät.

Der Spieler platzierte eine Wette und der Server schickte die versteckte Zahl und das „Salt“ an den Smart Contract. Vereinfacht gesagt deckte er die Karten auf. Danach überprüfte der Server die Zahlen und entschied, ob der Benutzer gewann oder verlor.

Wenn der Server keine Zahl oder „Salt“ zur Verifizierung gesendet hat, hat der Benutzer gewonnen. In diesem Fall war es für jedes Spiel erforderlich, im Voraus einen Smart Contract bereitzustellen und potenzielle Gewinne darin einzubeziehen. Es stellte sich als umständlich, zeitaufwändig und teuer heraus. Zu diesem Zeitpunkt gab es keine andere sichere Lösung.

Kürzlich schlug das Tradisys-Team vor, dem Waves-Protokoll eine Funktion hinzuzufügen rsaVerify(). Es prüft die Gültigkeit der RSA-Signatur anhand des öffentlichen und privaten Schlüssels. Infolgedessen wurde die Funktion hinzugefügt.

Wir haben drei Spiele entwickelt: Sagt Roller, Coin Flip и Reiten Sie auf Wellen. Jedes implementiert die Zufallszahlentechnologie. Lassen Sie uns herausfinden, wie es funktioniert.

RSA-Zufall auf Blockchain

Schauen wir uns die Generierung einer Zufallszahl am Beispiel von Ride on Waves an. Der Smart Contract kann gefunden werden hier.

Gehen Sie zur Registerkarte Skript und dann Dekompiliert. Sie sehen den Smart-Contract-Code (auch bekannt als Skript).

RSA-Zufall auf Blockchain

Der Smart-Contract-Code enthält eine Reihe von Funktionen. Diejenigen, die als @Callable markiert sind, können mit gestartet werden Aufruftransaktionen. Uns interessieren zwei Funktionen: Wette и zurückziehen:

  • Funktionswette (playerChoice)
  • Funktion Rückzug(gameId,rsaSign)

1. Der Benutzer wählt die Länge des Segments und die Einsatzhöhe aus.

RSA-Zufall auf Blockchain

2. Der Kunde erstellt eine Wettfunktion. Für das Bild oben wäre es so bet("50").

3. Der Client sendet eine Invocation-Transaktion an die Smart-Contract-Adresse (Broadcast InvocationTx). Die Transaktion enthält die Wettfunktion als Aufrufparameter. Das bedeutet, dass die Invocation-Transaktion die Ausführung der Wettfunktion (Auswahl: String) auf dem Smart Contract auslöst.

RSA-Zufall auf Blockchain

4. Betrachten Sie die Wettfunktion:

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

Die Funktion schreibt ein neues Spiel in den Zustand des Smart Contracts. Nämlich:

  • Eindeutige Kennung für ein neues Spiel (Spiel-ID)
  • Spielstatus = EINGEREICHT
  • Wahl des Spielers (Segmentlänge 50)
  • Öffentlicher Schlüssel
  • Potenzielle Gewinne (abhängig vom Einsatz des Spielers)

RSA-Zufall auf Blockchain

So sieht ein Datensatz in der Blockchain aus (Schlüsselwert):

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

„Schlüssel“ (Schlüssel) – Spiel-ID neues Spiel. Die restlichen Daten sind in der Zeile des Feldes „Wert“ enthalten. Diese Einträge werden in der Registerkarte gespeichert Datum Smart-Vertrag:

RSA-Zufall auf Blockchain

RSA-Zufall auf Blockchain

5. Der Server „schaut“ sich den Smart Contract an und findet die gesendete Transaktion (neues Spiel) mithilfe der Blockchain-API. Die Game-ID des neuen Spiels ist bereits in der Blockchain hinterlegt und kann daher nicht mehr verändert oder beeinflusst werden

6. Der Server generiert eine Auszahlungsfunktion (gameId, rsaSign). Zum Beispiel so:

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

7. Der Server sendet eine Invocation-Transaktion an den Smart Contract (Broadcast InvocationTx). Die Transaktion enthält einen Aufruf der gebildeten Auszahlungsfunktion (gameId, rsaSign):

RSA-Zufall auf Blockchain

Die Funktion enthält Spiel-ID neues Spiel und das Ergebnis der RSA-Signierung einer eindeutigen Kennung mit einem privaten Schlüssel. Das Signaturergebnis bleibt unverändert.

Was bedeutet das?

Wir nehmen den gleichen Wert (Spiel-ID) und wenden die RSA-Signaturmethode darauf an. Wir werden immer das gleiche Ergebnis erzielen. So funktioniert der RSA-Algorithmus. Die endgültige Zahl kann nicht manipuliert werden, da die Spiel-ID und das Ergebnis der RSA-Anwendung nicht bekannt sind. Es ist auch sinnlos, eine Zahl auszuwählen.

8. Blockchain akzeptiert die Transaktion. Es führt die Auszahlungsfunktion aus (gameId, rsaSign)

9. Innerhalb der Auszahlungsfunktion erfolgt eine Auszahlung GenerateRandInt-Funktionen (gameId, rsaSign). Dies ist ein Zufallszahlengenerator

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

and - und es gibt eine Zufallszahl.

Zunächst wird der String genommen, der das Ergebnis der RSA-Signatur ist Spiel-ID Privat Schlüssel (rsaSign). Dann mit SHA-256 gehasht (sha256(rsaSign)).

Wir können das Ergebnis der Signatur und des anschließenden Hashings nicht vorhersagen. Daher ist es unmöglich, die Generierung einer Zufallszahl zu beeinflussen. Um eine Zahl in einem bestimmten Bereich (z. B. von 1 bis 100) zu erhalten, verwenden Sie die Konvertierungsfunktion toInt und %100 (ähnlich wie mod).

Am Anfang des Artikels haben wir die Funktion erwähnt rsaVerify(), mit dem Sie die Gültigkeit einer RSA-Signatur mithilfe eines privaten Schlüssels anhand eines öffentlichen Schlüssels überprüfen können. Hier ist der GenerateRandInt(gameId,rsaSign)-Teil:

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

Der öffentliche Schlüssel RSAPUBLIC und der rsaSign-String werden an die Eingabe übergeben. Die Signatur wird auf Gültigkeit überprüft. Die Nummer wird generiert, wenn die Prüfung erfolgreich ist. Andernfalls geht das System davon aus, dass die Signatur ungültig ist (ungültige RSA-Signatur).

Der Server muss die Spiel-ID mit einem privaten Schlüssel signieren und innerhalb von 2880 Blöcken eine gültige Rsa-Signatur senden. Der Parameter wird bei der Bereitstellung des Smart Contracts konfiguriert. Wenn innerhalb der vorgegebenen Zeit nichts passiert, gewinnt der Benutzer. In diesem Fall muss der Gewinn selbst an Ihre Adresse gesendet werden. Es stellt sich heraus, dass es „für den Server nicht rentabel ist, zu betrügen“, da dies zu Verlusten führt. Unten finden Sie ein Beispiel.

RSA-Zufall auf Blockchain

Der Benutzer spielt Sagt Roller. Ich habe 2 der 6 Seiten des Würfels gewählt, der Einsatz beträgt 14 WELLEN. Wenn der Server innerhalb der angegebenen Zeit (2880 Blöcke) keine gültige RSA-Signatur an den Smart Contract sendet, erhält der Benutzer 34.44 WAVES.

Um Zahlen in Spielen zu generieren, nutzen wir ein Orakel – ein externes, nicht-Blockchain-System. Der Server führt eine RSA-Signatur der Spiel-ID durch. Der Smart Contract prüft die Gültigkeit der Signatur und ermittelt den Gewinner. Wenn der Server nichts sendet, gewinnt automatisch der Benutzer.

Dies ist eine ehrliche Generierungsmethode, da eine Manipulation technisch unmöglich ist. Alle Tradisys-Spiele funktionieren auf Basis des beschriebenen Algorithmus. So funktionieren Blockchain-Spiele. Alles ist transparent und überprüfbar. In keiner anderen Blockchain gibt es Analogien zu einem solchen System. Das ist ein fairer Zufall.

Source: habr.com

Kommentar hinzufügen